如何从头实现一个node.js的koa框架

2020-06-17 06:09:13易采站长站整理

然后我们来测试一下目前为止的框架。修改example.js如下:


let simpleKoa = require('./application');
let app = new simpleKoa();
app.use(async ctx => {
ctx.body = 'hello ' + ctx.query.name;
});
app.listen(3000, () => {
console.log('listening on 3000');
});

可以看到这个时候我们通过app.use传入的已经不再是原生的function (req, res)回调函数,而是koa2中的async函数,接收ctx作为参数。为了测试,在浏览器访问localhost:3000?name=tom,可以看到返回了’hello tom’,符合预期。

这里再插入分析一个知识概念。从刚才的实现中,我们知道了this.context是我们的中间件中上下文ctx对象的原型。因此在实际开发中,我们可以将一些常用的方法挂载到this.context上面,这样,在中间件ctx中,我们也可以方便的使用这些方法了,这个概念就叫做ctx的扩展,一个例子是阿里的egg.js框架已经把这个扩展机制作为一部分,融入到了框架开发中。

下面就展示一个例子,我们写一个echoData的方法作为扩展,传入errno, data, errmsg,能够给客户端返回结构化的消息结果:


let SimpleKoa = require('./application');
let app = new SimpleKoa();
// 对ctx进行扩展
app.context.echoData = function (errno = 0, data = null, errmsg = '') {
this.res.setHeader('Content-Type', 'application/json;charset=utf-8');
this.body = {
errno: errno,
data: data,
errmsg: errmsg
};
};
app.use(async ctx => {
let data = {
name: 'tom',
age: 16,
sex: 'male'
}
// 这里使用扩展,方便的返回utf-8格式编码,带有errno和errmsg的消息体
ctx.echoData(0, data, 'success');
});
app.listen(3000, () => {
console.log('listenning on 3000');
});

主线三:中间件机制

到目前为止,我们成功封装了http server,并构造了context, request, response对象。但最重要的一条主线却还没有实现,那就是koa的中间件机制。

关于koa的中间件洋葱执行模型,koa 1中使用的是generator + co.js执行的方式,koa 2中则使用了async/await。关于koa 1中的中间件原理,我曾写过一篇文章进行解释,请移步:深入探析koa之中间件流程控制篇

这里我们实现的是基于koa 2的,因此再描述一下原理。为了便于理解,假设我们有3个async函数:


async function m1(next) {
console.log('m1');
await next();
}
async function m2(next) {
console.log('m2');
await next();
}
async function m3() {
console.log('m3');
}

我们希望能够构造出一个函数,实现的效果是让三个函数依次执行。首先考虑想让m2执行完毕后,await next()去执行m3函数,那么显然,需要构造一个next函数,作用是调用m3,然后作为参数传给m2