前端全栈必会node框架koa。。。

啥是koa?那个美女好像也叫koa

Koa2是现在最流行的基于Node.js平台的web开发框架;Koa 应用程序是一个包含一组中间件函数的对象,它是按照类似堆栈的方式组织和执行的。

const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
  ctx.body = 'Hello World';
});
app.on('error', err => {
  log.error('server error', err)
});

app.listen(3000);
复制代码

koa中间件以更传统的方式级联;那和express的中间件有什么区别呢?

  • 区别只有一点express的中间件中存在异步操作时不会等待;而koa会等待异步操作完成后;才会执行下一个中间件;

express和koa的区别

let express = require('express');
let app = express();
app.use(async (req, res, next) => {
  console.log(1);
  await next();
  console.log(2);
});
app.use(async (req, res, next) => {
  console.log(3);
  await new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('异步');
      resolve()
    }, 100);
  })
  await next();
  console.log(4);

});
app.listen(3000);
// 1 3 2 异步 4  
//遇到异步不会等待 直接执行;打乱原来的洋葱模型

复制代码
  • koa
let Koa = require('Koa');
let app = new Koa();
app.use( async (ctx, next) => {
    console.log(1);
    await next();
    console.log(2)
});
app.use(async (ctx, next) => {
    console.log(3);
      await new Promise((resolve, reject) => {
          setTimeout(() => {
              console.log('异步');
              resolve()
          }, 100);
      })
    await next();
    console.log(4)
})
app.listen(3000);
// 1 3 异步 4 2  

复制代码

koa使用中间件获取请求体

const bodyParser = require('koa-bodyparser');
app.use(bodyParser());
app.use(async (ctx)=>{
    let body=ctx.request.body;//得到请求体
})

复制代码

使用中间件获取包含文件的请求体

const bodyParser = require('koa-better-body');
et convert = require('koa-convert'); // 将1.0的中间件 转化成2.0中间件
app.use(convert(bodyParser({
    uploadDir: path.join(__dirname, 'uploads'),
    keepExtensions: true
})));
app.use(async (ctx)=>{
    let body=ctx.request.fields;//得到文件信息
})
复制代码

路由中间件

//一级路由
const Router = require('koa-router');
let user = new Router();
user.get('/user', function (ctx) {
    ctx.body = 'get user ';
}).get('/query/:id', function (ctx) {
    ctx.body = ctx.params;
}).post('/user', function (ctx) {
    ctx.body = 'post user ';
}).get('/home', function (ctx) {
    ctx.body = 'get home ';
});
app.use(user.routes());

//多级路由
let user = new Router();
user.get('/add', function (ctx) {
    ctx.body = 'get user add ';
});

let article = new Router();
article.get('/add', function (ctx) {
    ctx.body = 'get article add ';
});

let router = new Router();
router.use('/user', user.routes()); //  /user/add
router.use('/article', article.routes()); ///article/add
app.use(router.routes());
复制代码

koa自带存取cookie方法

//ctx.cookies.get(name,[optins]):读取上下文请求中的cookie。
//ctx.cookies.set(name,value,[options]):在上下文中写入cookie。
app.keys = ['hello'];
ctx.cookies.set('name','sss',{
    domain:'localhost', // 在哪个域名下设置cookie
    path:'/',// 在哪个路径下设置cookie
    maxAge:10*1000, // 最大存活时间
    httpOnly:false, //是否只用http请求中获得
    overwrite:true,//是否允许重写
    signed:true//签名要app.keys 
  });

expires:cookie失效时间

复制代码

session

let Koa = require('koa');
let app = new Koa();
let Router = require('koa-router');
const session = require('koa-session');
app.keys = ['key']
app.use(session({},app)); // 用了这个中间件 可以在ctx上增加session属性
router.get('/cross', (ctx,next)=> {
  let n = ctx.session.n || 0;
  ctx.session.n = ++n;
  ctx.body = ctx.session.n;
});
app.use(router.routes());
app.use(router.allowedMethods()); // 405
复制代码

模板引擎

let Koa = require('koa');
let app = new Koa();
let Router = require('koa-router');
let router = new Router();
let views = require('koa-views');
app.use(views(__dirname, {
  map:{'html':'ejs'}//识别HTML
}));
router.get('/',async (ctx,next)=>{
  // 如果不写return 这个函数执行完就结束了 模板还没有被渲染,ctx.body = ''
  // 如果使用return会等待这个返回的promise执行完后才把当前的promise完成
   return ctx.render('ejs.html',{title:'标题'});
})
app.use(router.routes());
app.listen(3000); 

复制代码

静态资源中间件

const static = require('koa-static')
app.use(static(path.join( __dirname,  'public')))
app.use( async ( ctx ) => {
  ctx.body = 'Not Found'
})
复制代码

自己实现koa

let EventEmitter = require('events');
let http = require('http');
let context = require('./context');
let request = require('./request');
let response = require('./response');
class Koa extends EventEmitter{
  constructor(){
    super();
    this.middlewares = [];
    this.context = context;
    this.request = request;
    this.response = response;
  }
  use(fn){
    this.middlewares.push(fn);
  }
  createContext(req,res){ 
    let ctx = Object.create(this.context); 
    let request = Object.create(this.request); 
    let response = Object.create(this.response);
    ctx.request = request; 
    ctx.response = response; 
    ctx.req = ctx.request.req =  req;
    ctx.res = ctx.response.res =  res;
    return ctx;
  }
  compose(middlewares,ctx){
    // express
    function dispatch(index) {
      if (index === middlewares.length) return Promise.resolve();
      let route = middlewares[index];
      // 把每个中间件都包装成promise
      return Promise.resolve(route(ctx, () => dispatch(index+1)));
    }
    return dispatch(0);
  }
  handleRequest(req,res){
    let ctx = this.createContext(req,res);
    res.statusCode = 404;
    // this.fn(context); 需要把中间件函数组合起来

    let fn = this.compose(this.middlewares,ctx);
    let Stream = require('stream');
    fn.then(data=>{
      if(typeof ctx.body == 'object'){
        res.setHeader('Content-Type', 'application/json;charset=utf8');
        res.end(JSON.stringify(ctx.body))
      } else if (ctx.body instanceof Stream){
        ctx.body.pipe(res);
      }
      else if (typeof ctx.body === 'string' || Buffer.isBuffer(ctx.body)) {
        res.setHeader('Content-Type', 'text/html;charset=utf8');
        res.end(ctx.body);
      } else {
        res.end('Not found')
      }
    }).catch(err=>{
      this.emit('error',err);//
      res.statusCode = 500;
      res.end(`server error`);
    })
  }
  listen(){
    let server = http.createServer(this.handleRequest.bind(this));
    server.listen(...arguments);
  }
}

module.exports = Koa;


//ctx
let proto = {}
// 代理的作用
function defineGetter(property,name) {
  proto.__defineGetter__(name,function () {
    return this[property][name];
  })
}
function defineSetter(property,name) {
  // ctx.body = xxx
  // ctx.response.body = xxx
  proto.__defineSetter__(name,function (val) {
    this[property][name] = val;
  })
}
// ctx.query = ctx.request.query
defineGetter('request','query');
defineGetter('response','body');
defineSetter('response','body');
module.exports = proto;


//request
let request = { // 封装求的方法
  get url(){
    return this.req.url
  },
  get path(){
    let {pathname:path} = require('url').parse(this.req.url);
    return path;
  },
  get query(){
    let { query } = require('url').parse(this.req.url,true);
    return query;
  }
  // .........
}

module.exports = request;


//response
let response = {
  get body(){
    return this._body;
  },
  set body(value){
    this.res.statusCode = 200;
    this._body = value;
  }
}
module.exports = response;
复制代码

你可能感兴趣的:(前端全栈必会node框架koa。。。)