说明
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);