koa2中间件的简单实现
说明
-
本次的简单实现重点在中间件的原理上(
compose函数
),而其他部分的实现就忽略了很多细节,只是让代码能跑起来。 -
与
express
不同,koa2
的路由处理与它本身是分开的(路由处理用koa-router
)。这里的内容不包括路由处理。 -
本次的实现内容包括koa的
use
,listen
和中间件的洋葱圈模型。
koa中间件执行机制
koa2中间件使用的是洋葱圈模型
。这里附上一张网络上广为流传的图:
从这张图也能知道个大概意思:请求从最外层传到最里层,响应从最里层逐层往外传递。
下面来看一个经典的例子理解一下(如果之间不了解koa中间件机制的话,请跟着注释一步步地走):
const Koa = require('koa');
const app = new Koa();
// logger
app.use(async (ctx, next) => {
// 1. request: 请求处理开始!执行这一行代码,然后往下走
console.log('第一层洋葱 - 开始')
// 2. request: 遇到一个异步函数,进入这个中间件
await next();
// 12. response: 第二个中间件执行结束后返回这里,代码往下执行,获得之前在ctx中存储的变量
const rt = ctx.response.get('X-Response-Time');
// 13. response: 控制台打印 请求方法 请求路径 响应时间
console.log(`${
ctx.method} ${
ctx.url} - ${
rt}`);
// 14. response: 所有中间件执行结束!
console.log('第一层洋葱 - 结束')
});
// x-response-time
app.use(async (ctx, next) => {
// 3. request: 从第一个中间件进入了这里,执行这一行代码,然后往下走
console.log('第二层洋葱 - 开始')
// 4. request: 继续执行代码,存储当前时间戳
const start = Date.now();
// 5. request: 又遇到一个异步函数,进入这第三个中间件
await next();
// 9. response: 第三个中间件执行结束后返回这里,代码往下执行,获得 ms 变量:第三个中间件的执行时间
const ms = Date.now() - start;
// 10. response: 设置 ctx属性,值可以从ctx.response中拿到
ctx.set('X-Response-Time', `${
ms}ms`);
// 11. response: 第二个中间件执行结束,返回到第一个中间件的next()下方
console.log('第二层洋葱 - 结束')
});
// response
app.use(async ctx => {
// 6. request: 从第二个中间件进入到了这里,执行这一行代码,然后往下走
console.log('第三层洋葱 - 开始')
// 7. 收到响应数据,将 Hello World 返回给前端
ctx.body = 'Hello World';
// 8. response: 第三个中间件执行结束,响应阶段开始,返回到第二个中间件的 next() 下方
console.log('第三层洋葱 - 结束')
});
// 该函数优先于上面所有函数的执行!
app.listen(8000, () =>