乐趣区

关于express:第四代Express框架koa简介

简介

相熟 Spring MVC 的敌人应该都分明 Spring MVC 是基于 servlet 的代码框架,这是最传统的 web 框架。而后在 Spring5 中引入了 Spring WebFlux,这是基于 reactive-netty 的异步 IO 框架。

同样的,nodejs 在最后的 Express 3 根底上倒退起来了异步的 koa 框架。koa 应用了 promises 和 aysnc 来防止 JS 中的回调天堂,并且简化了错误处理。

明天咱们要来介绍一下这个优良的 nodejs 框架 koa。

koa 和 express

koa 不再应用 nodejs 的 req 和 res,而是封装了本人的 ctx.request 和 ctx.response。

express 能够看做是 nodejs 的一个利用框架,而 koa 则能够看成是 nodejs 的 http 模块的形象。

和 express 提供了 Middleware,Routing,Templating,Sending Files 和 JSONP 等个性不同的是,koa 的性能很繁多,如果你想应用其余的一些性能比方 routing,sending files 等性能,能够应用 koa 的第三方中间件。

koa 并不是来替换 express 的,就像 spring webFlux 并不是用来替换 spring MVC 的。koa 只是用 Promises 改写了控制流,并且防止了回调天堂,并提供了更好的异样解决机制。

koa 应用介绍

koa 须要 node v7.6.0+ 版本来反对 ES2015 和 async function。

咱们看一个最最简略的 koa 利用:

const Koa = require('koa');
const app = module.exports = new Koa();

app.use(async function(ctx) {ctx.body = 'Hello World';});

if (!module.parent) app.listen(3000);

koa 应用程序就是一个蕴含了很多个中间件的对象,这些中间件将会依照相似 stack 的执行程序一个相应 request。

中间件的级联关系

koa.use 中传入的是一个 function,咱们也能够称之为中间件。

koa 能够 use 很多个中间件,举个例子:

const Koa = require('koa');
const app = new Koa();

app.use(async (ctx, next) => {await next();
  console.log('log3');
});

app.use(async (ctx, next) => {await next();
  console.log('log2');
});

app.use(async ctx => {console.log('log3');
});

app.listen(3000);

下面的例子中,咱们调用了屡次 next, 只有咱们调用 next,调用链就会传递到下一个中间件进行解决,始终到某个中间件不再调用 next
为止。

下面的代码运行输入:

log1
log2
log3

koa 的构造函数

咱们看下 koa 的构造函数:

constructor(options) {super();
    options = options || {};
    this.proxy = options.proxy || false;
    this.subdomainOffset = options.subdomainOffset || 2;
    this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For';
    this.maxIpsCount = options.maxIpsCount || 0;
    this.env = options.env || process.env.NODE_ENV || 'development';
    if (options.keys) this.keys = options.keys;
    this.middleware = [];
    this.context = Object.create(context);
    this.request = Object.create(request);
    this.response = Object.create(response);
    // util.inspect.custom support for node 6+
    /* istanbul ignore else */
    if (util.inspect.custom) {this[util.inspect.custom] = this.inspect;
    }
  }

能够看到 koa 接管上面几个参数:

  • app.env 默认值是 NODE_ENV 或者 development
  • app.keys 为 cookie 签名的 keys

看下怎么应用:

app.keys = ['secret1', 'secret2'];
app.keys = new KeyGrip(['secret1', 'secret2'], 'sha256');

ctx.cookies.set('name', 'jack', { signed: true});
  • app.proxy 是否反对代理
  • app.subdomainOffset 示意子域名是从第几级开始的,这个参数决定了 request.subdomains 的返回后果,默认值为 2
  • app.proxyIpHeader proxy ip header 默认值是 X -Forwarded-For
  • app.maxIpsCount 从 proxy ip header 读取的最大 ip 个数,默认值是 0 示意无限度。

咱们能够这样用:

const Koa = require('koa');
const app = new Koa({proxy: true});

或者这样用:

const Koa = require('koa');
const app = new Koa();
app.proxy = true;

启动 http server

koa 是一种 web 框架,web 框架就须要开启 http 服务,要启动 http 服务,须要调用 nodejs 中的 Server#listen()办法。

在 koa 中,咱们能够很不便的应用 koa#listen 办法来启动这个 http server:

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

下面的代码相当于:

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

当然你能够同时创立 http 和 https 的服务:

const http = require('http');
const https = require('https');
const Koa = require('koa');
const app = new Koa();
http.createServer(app.callback()).listen(3000);
https.createServer(app.callback()).listen(3001);

自定义中间件

koa 中的中间件是参数值为 (ctx, next) 的 function。在这些办法中,须要手动调用 next()以传递到下一个 middleware。

上面看一下自定义的中间件:

async function responseTime(ctx, next) {const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.set('X-Response-Time', `${ms}ms`);
}

app.use(responseTime);
  • 给中间件起个名字:

尽管中间件 function 只接管参数(ctx, next),然而我能够将其用一个 wrapper 办法包装起来,在 wrapper 办法中,咱们给中间件起个名字:

function logger(name) {return async function logger(ctx, next) {console.log(name);
      await next();};    
}
  • 自定义中间件的扩大:

下面的 wrapper 创立形式还有另外一个益处,就是能够在自定义中间件中拜访传入的参数,从而能够依据传入的参数,对自定义中间件进行扩大。

function logger(format) {
  format = format || ':method":url"';

  return async function (ctx, next) {
    const str = format
      .replace(':method', ctx.method)
      .replace(':url', ctx.url);

    console.log(str);

    await next();};
}

app.use(logger());
app.use(logger(':method :url'));
  • 组合多个中间件:

当有多个中间件的状况下,咱们能够应用 compose 将其合并:

const compose = require('koa-compose');
const Koa = require('koa');
const app = module.exports = new Koa();

// x-response-time

async function responseTime(ctx, next) {const start = new Date();
  await next();
  const ms = new Date() - start;
  ctx.set('X-Response-Time', ms + 'ms');
}

// logger

async function logger(ctx, next) {const start = new Date();
  await next();
  const ms = new Date() - start;
  if ('test' != process.env.NODE_ENV) {console.log('%s %s - %s', ctx.method, ctx.url, ms);
  }
}

// response

async function respond(ctx, next) {await next();
  if ('/' != ctx.url) return;
  ctx.body = 'Hello World';
}

// composed middleware

const all = compose([
  responseTime,
  logger,
  respond
]);

app.use(all);

if (!module.parent) app.listen(3000);

异样解决

在 koa 中怎么进行异样解决呢?

通用的办法就是 try catch:


app.use(async (ctx, next) => {
  try {await next();
  } catch (err) {
    err.status = err.statusCode || err.status || 500;
    throw err;
  }
});

当然你也能够自定义默认的 error 处理器:

app.on('error', err => {log.error('server error', err)
});

咱们还能够传入上下文信息:

app.on('error', (err, ctx) => {log.error('server error', err, ctx)
});

本文作者:flydean 程序那些事

本文链接:http://www.flydean.com/koa-startup/

本文起源:flydean 的博客

欢送关注我的公众号:「程序那些事」最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

退出移动版