koa第二篇:中间件级联与await next()

说明

koa 把很多 async 函数组成一个处理链,每个async函数都可以做一些自己的事情,然后用 await next() 来调用下一个 async 函数。我们把每个 async 函数称为 middleware (中间件),这些 middleware 可以组合起来,完成很多有用的功能。

下面的 例子 在页面中返回 “Hello World”,然而当请求开始时,请求先经过 x-response-time 和 logging 中间件,并记录中间件执行起始时间。

然后将控制权交给 reponse 中间件。当一个中间件调用next()函数时,函数挂起并控件传递给定义的下一个中间件。

在没有更多的中间件执行下游(downstream)之后,堆栈将退出,并且每个中间件被恢复以执行其上游行为。

After there are no more middleware to execute downstream, the stack will unwind and each middleware is resumed to perform its upstream behaviour.

多个中间件会形成一个栈结构(middle stack),以【先进后出】(first-in-last-out)的顺序执行。

示例

完整例子代码( app.js )如下:

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

// x-response-time 中间件

app.use(async (ctx, next) => {
    console.log('\n开始 x-response-time');
    const start = Date.now();
    await next(); // 调用下一个中间件:logger(等待下一个异步函数返回)
    const ms = Date.now() - start;
    ctx.set('X-Response-Time', `${ms}ms`); // 设置响应头
    console.log('结束 x-response-time\n');
});

// logger 中间件

app.use(async (ctx, next) => {
    console.log('开始 logger');
    const start = Date.now();
    await next(); // 调用下一个中间件:response(等待下一个异步函数返回)
    const ms = Date.now() - start;
    console.log(`\u0020\u0020\u0020\u0020\u0020${ctx.method} ${ctx.url} - ${ms} ms`); // \u0020 为空格
    console.log('结束 logger');
});

// response 中间件

app.use(async ctx => {
    console.log('开始 response');
    ctx.body = 'Hello World';
    console.log('结束 response');
    // 没有更多的中间件执行,堆栈将展开并且每个中间件恢复执行其上游行为
});

app.listen(3000);
console.log('app started at port 3000...');

运行并访问,我们在控制台可以看到:

E:\xushanxiang\nodeproj\koaproj>npm start

> koaproj@1.0.0 start E:\xushanxiang\nodeproj\koaproj
> node app.js

app started at port 3000...

开始 x-response-time
开始 logger
开始 response
结束 response
     GET / - 7 ms
结束 logger
结束 x-response-time


开始 x-response-time
开始 logger
开始 response
结束 response
     GET /favicon.ico - 4 ms
结束 logger
结束 x-response-time

怎么样,执行流程是不是很明了?

补充

如果一个中间件 没有调用 await next(),会怎么办?答案是后续的 middleware 将不再执行了。

这种情况也很常见,例如,一个检测用户权限的 middleware 可以决定是否继续处理请求,还是直接返回403错误:

app.use(async (ctx, next) => {
    if (await checkUserPermission(ctx)) {
        await next();
    } else {
        ctx.response.status = 403;
    }
});

到这里,koa 算是入门了。

拓展

koa-compose 模块可以将多个中间件合成为一个。

const compose = require('koa-compose');

const logger = (ctx, next) => {
  console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`);
  next();
}

const main = ctx => {
  ctx.response.body = 'Hello World';
};

const middlewares = compose([logger, main]);
app.use(middlewares);

已发布

分类

,

来自

标签: