koa是一个基于node实现的一个新的web框架,它是由express框架的原班人马打造的。它的特点是优雅、简洁、表达力强、自由度高。它更express相比,它是一个更轻量的node框架,因为它所有功能都通过插件实现,这种插拔式的架构设计模式,很符合unix哲学。
koa框架现在更新到了2.x版本,本文从零开始,循序渐进,讲解koa2的框架源码结构和实现原理,展示和详解koa2框架源码中的几个最重要的概念,然后手把手教大家亲自实现一个简易的koa2框架,帮助大家学习和更深层次的理解koa2,看完本文以后,再去对照koa2的源码进行查看,相信你的思路将会非常的顺畅。
本文所用的框架是koa2,它跟koa1不同,koa1使用的是generator+co.js的执行方式,而koa2中使用了async/await,因此本文的代码和demo需要运行在node 8版本及其以上,如果读者的node版本较低,建议升级或者安装babel-cli,用其中的babel-node来运行本文涉及到的代码。
koa源码结构
上图是koa2的源码目录结构的lib文件夹,lib文件夹下放着四个koa2的核心文件:application.js、context.js、request.js、response.js。
application.js
application.js是koa的入口文件,它向外导出了创建class实例的构造函数,它继承了events,这样就会赋予框架事件监听和事件触发的能力。application还暴露了一些常用的api,比如toJSON、listen、use等等。
listen的实现原理其实就是对http.createServer进行了一个封装,重点是这个函数中传入的callback,它里面包含了中间件的合并,上下文的处理,对res的特殊处理。
use是收集中间件,将多个中间件放入一个缓存队列中,然后通过koa-compose这个插件进行递归组合调用这一些列的中间件。
context.js
这部分就是koa的应用上下文ctx,其实就一个简单的对象暴露,里面的重点在delegate,这个就是代理,这个就是为了开发者方便而设计的,比如我们要访问ctx.repsponse.status但是我们通过delegate,可以直接访问ctx.status访问到它。
request.js、response.js
这两部分就是对原生的res、req的一些操作了,大量使用es6的get和set的一些语法,去取headers或者设置headers、还有设置body等等,这些就不详细介绍了,有兴趣的读者可以自行看源码。
实现koa2的四大模块
上文简述了koa2源码的大体框架结构,接下来我们来实现一个koa2的框架,笔者认为理解和实现一个koa框架需要实现四个大模块,分别是:
-
封装node http server、创建Koa类构造函数
-
构造request、response、context对象
-
中间件机制和剥洋葱模型的实现
-
错误捕获和错误处理
下面我们就逐一分析和实现。
模块一:封装node http server和创建Koa类构造函数
阅读koa2的源码得知,实现koa的服务器应用和端口监听,其实就是基于node的原生代码进行了封装,如下图的代码就是通过node原生代码实现的服务器监听。
let http = require('http');
let server = http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world');
});
server.listen(3000, () => {
console.log('listenning on 3000');
});
我们需要将上面的node原生代码封装实现成koa的模式:
const http = require('http');
const Koa = require('koa');
const app = new Koa();
app.listen(3000);
实现koa的第一步就是对以上的这个过程进行封装,为此我们需要创建application.js实现一个Application类的构造函数:
let http = require('http');
class Application {
constructor() {
this.callbackFunc;
}
listen(port) {
let server = http.c