koa-connect相信有些早期写Koa2的童鞋比较熟悉,它的作用就是在Koa2中可以使用Express社区的中间件,起到了一个中转或者适配的作用。
那么接下来我们去看下源码是如何实现的。
源码
首先我们简单了解express常见的中间件用法有哪些?
app.get('/', [
// 带有next回调、进入下一个中间件
function (req, res, next) {
fs.readFile('/maybe-valid-file', 'utf-8', function (err, data) {
res.locals.data = data
next(err)
})
},
// 基本款、不带next回调
function (req, res) {
res.locals.data = res.locals.data.split(',')[1]
res.send(res.locals.data)
}
])
那么对应Koa2中间件长什么样呢?
// ctx、next
app.use(async (ctx, next) => {
await next();
const rt = ctx.response.get('X-Response-Time');
console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});
好了,这里记得提下在Koa中,next是一个包装的Promise。
那么接下来我们就去看下源码对应实现。
"use strict";
const noop = () => { };
// 不带next回调的express中间件包装函数
function noCallbackHandler(ctx, connectMiddleware, next) {
// next => Koa2中间件函数
// 可见express中间件的req、res与ctx.req、ctx.res一致
connectMiddleware(ctx.req, ctx.res, noop);
// 直接进入下一个Koa2中间件流程
return next();
}
// 带next回调的express中间件包装函数
function withCallbackHandler(ctx, connectMiddleware, next) {
// 返回Promise 符合Koa2中间件规范 await next
return new Promise((resolve, reject) => {
connectMiddleware(ctx.req, ctx.res, (err) => {
// err为业务中抛出的error
// 这里对err的处理 符合express error handing
// https://www.expressjs.com.cn/guide/error-handling.html
if (err)
reject(err);
else
// 正常进入下一个中间件
resolve(next());
});
});
}
// 暴露的方法
// connectMiddleware:中间件函数
function koaConnect(connectMiddleware) {
// 根据connectMiddleware.length判断是否带next回调。
// 但是如果你中间件函数使用的是arguments或者rest就会判断有问题。
const handler = connectMiddleware.length < 3 ? noCallbackHandler : withCallbackHandler;
// 最后返回的就是符合Koa2 中间件签名的函数
return function koaConnect(ctx, next) {
return handler(ctx, connectMiddleware, next);
};
}
module.exports = koaConnect;
好了,今天就到这结束了,下期见。
ps:如果你对node也有兴趣,欢迎关注我公众号:xyz编程日记。