1.简介

koa框架是一个遵循洋葱模型的轻量级的nodejs框架,将大部分工作都抛给中间件来解决,框架只专一于compose各个中间件,并依照use注册的程序一一执行中间件。

2.装置应用

装置:npm install koa -s
应用:

const Koa = require('koa');const app = new Koa;app.listen(3000);

3.中间件的应用

const Koa  = require('koa');const mount = require('koa-mount');const app = new Koa();app.use(mount('/api', function() {      .....}));app.listen(80);

以上代码应用了koa-mount来进行进行路由解决,应用koa实例上的use办法将mount函数返回的函数注册为中间件。以下是koa中use函数。

  use(fn) {    if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');    if (isGeneratorFunction(fn)) {      deprecate('Support for generators will be removed in v3. ' +                'See the documentation for examples of how to convert old middleware ' +                'https://github.com/koajs/koa/blob/master/docs/migration.md');      fn = convert(fn);    }    debug('use %s', fn._name || fn.name || '-');    this.middleware.push(fn);    return this;  }

能够看到,一个函数中间件在use函数中先是判断是否为generator函数,如果是,应用koa-convert转换,最终都会放入koa实例的middleware数组中保留,供后续调用。
a.说一下isGeneratorFunction函数,这个函数的思路是通过Function动态创建一个generate函数,而后取其原型与传入的函数的原型比照,如果雷同阐明传入函数就是generate函数。
b.再说一下convert函数,这个函数在koa-convert包中,就是外部又引入了co库,将传入的generate函数包裹,达到自执行的成果。

回过头说一下koa的listen函数,代码如下:

  listen(...args) {    debug('listen');    const server = http.createServer(this.callback());    return server.listen(...args);  }  callback() {    const fn = compose(this.middleware);    if (!this.listenerCount('error')) this.on('error', this.onerror);    const handleRequest = (req, res) => {      const ctx = this.createContext(req, res);      return this.handleRequest(ctx, fn);    };    return handleRequest;  }

能够看到,listen函数外部调用了node外围模块http,创立了一个http服务,并将本身的callback函数作为http服务的响应函数。
而callback函数外部则是通过compose将之前注册的中间件包裹,而后通过createContext将req和res封装到一个ctx中,逐层传入前面的中间件中。ctx内容如下:

4.request和response解决

如上所示,req和res被封装到了context中,在各个中间件都能够从参数中失去,中间件能够拿到两个参数:一个是context,各中间件能够通过它来进行通信和同步状态;第二个是next,调用它会执行后续中间件。应用示例如下:

const Koa = require('koa')const app = new Koa()//申明一个main中间件,如果你急于理解中间件能够跳转到(三)const main = (ctx,next) =>{if (ctx.request.accepts('json')) {    ctx.response.type = 'json';    ctx.response.body = { data: 'Hello World' };  } else if (ctx.request.accepts('html')) {    ctx.response.type = 'html';    ctx.response.body = '<p>Hello World</p>';  } else if (ctx.request.accepts('xml')) {    ctx.response.type = 'xml';    ctx.response.body = '<data>Hello World</data>';  } else{    ctx.response.type = 'text';    ctx.response.body = 'Hello World';  };}; //间接运行页面中会显示json格局,因为咱们没有设置申请头,所以每一种格局都是ok的。   app.use(main)//app.use()用来加载中间件。app.listen(3000)

能够看到,咱们给返回数据赋值能够间接应用’=‘赋值,在koa的response中body通过set属性,将设置进来的body值依照其type进行解决,如下。

  set body(val) {    const original = this._body;    this._body = val;    // no content    if (null == val) {      if (!statuses.empty[this.status]) this.status = 204;      if (val === null) this._explicitNullBody = true;      this.remove('Content-Type');      this.remove('Content-Length');      this.remove('Transfer-Encoding');      return;    }    // set the status    if (!this._explicitStatus) this.status = 200;    // set the content-type only if not yet set    const setType = !this.has('Content-Type');    // string    if ('string' === typeof val) {      if (setType) this.type = /^\s*</.test(val) ? 'html' : 'text';      this.length = Buffer.byteLength(val);      return;    }    // buffer    if (Buffer.isBuffer(val)) {      if (setType) this.type = 'bin';      this.length = val.length;      return;    }    // stream    if (val instanceof Stream) {      onFinish(this.res, destroy.bind(null, val));      if (original != val) {        val.once('error', err => this.ctx.onerror(err));        // overwriting        if (null != original) this.remove('Content-Length');      }      if (setType) this.type = 'bin';      return;    }    // json    this.remove('Content-Length');    this.type = 'json';  },

5.动态资源

应用koa-static中间件来解决动态资源,实例如下:
装置npm: npm install koa-static
应用:

const Koa = require('koa');const app = new Koa();const path = require('path');const serve = require('koa-static');const main = serve(path.join(__dirname));app.use(main);app.listen(3000);

参考资料:

https://zhuanlan.zhihu.com/p/67239164?utm_id=0