目标
本文主要通过一个简单的例子来解释koa的内部原理。
koa的一个简单例子
图1是Koa的一个简单例子,下文会对这个例子的每行代码背后的逻辑做详细分析。
图1 demo
koa内部文件组成
图2 Koa代码文件
图3 文件和具体类
koa内部
在图1的例子中,执行const app = new koa()时,实际上构造了一个Application实例,图4为Application构造方法,构造方法中创建了Context、Request、Response等类的运行实例。关于Context、Response、Request类及方法介绍请参考
https://koajs.com/
下文约定request代指Request类实例,response代指Response类实例,context代指Context类实例。
图4 Application构造方法
图1的例子中调用app.listen(3000)方法监听3000端口进来的http请求,listen方法内部创建了一个http.Server对象,并调用http.Server的listen方法。具体代码如图5。
图5 listen犯法
图5中this.callback方法的源码如下图6中所示
图6 callback
callback方法返回一个handleRequest函数,作为createServer的参数,当http.Server实例接收到一个http请求时,会将请求信息和请求响应对象传给handleRequest函数,具体指将http.IncomingMessage的实例req,和http.ServerResponse的实例res传给handleRequest函数。其中this.createContext函数的源码如下图7
http.IncomingMessage和http.ServerResponse信息可以参照node.js官网
图7 createContext
图7中createContext的主要作用是将请求信息和响应信息封装在Request和Response类的运行实例中,并创建上下文类Context实例。context对象包含了Application、Request、Response等实例的引用。在this.callback方法中还有另一行很重要的代码,如下代码片段1。
代码片段1
<code>const fn = compose(this.middleware);/<code>
可以从图4中Application的构造方法中知道this.middleware是一个数组,该数组用来存储app.use方法传入的中间件函数。Application的use方法具体代码实现细节如图8,其中最关键的一行代码是this.middleware.push(fn)。
图8 use
compose方法的代码实现包含在koa-compose包中,具体代码实现细节如图9
图9 compose
compose方法接收this.middleware数组,返回一个匿名函数,该函数接收两个参数,上下文实例context和一个next函数,执行该匿名函数会执行this.middleware数组中的所有中间件函数,然后在执行传入的next函数。匿名函数调用是在Application的callback方法中,在图6
图9 handleRequest
在this.handleRequest方法中创建了错误处理方法onError和返回响应的方法
<code>return fnMiddleware(ctx).then(handleResponse).catch(onerror);/<code>
执行fnMiddleware函数,实际上是执行之前传入所有中间件函数。在中间函数中可以拿到上下文对象的引用,通过上下文对象我们可以获取到经过封装的请求和响应实例,具体形式如图10。
图10 中间间函数例子
在中间件方法中可以设置响应头信息、响应内容。以及读取数据库,获取html模版等。将需要返回给用户端的数据赋值给上下文对象context的body属性。respond方法的具体实现如图11。
图11 respond
respond方法的主要作用是对返回的内容进行一些处理,然后调用node.js的http.ServerResponse实例的end方法,将具体内容返回给用户端。
request.js和response.js
在Application的createContext方法中,将node.js的请求(http.IncomingMessage)和响应对象(http.ServerResponse)分别赋值给了Request类和Response类实例对象。Request中主要包含了处理请求的方法(实际上都是get方法,或者获取器),获取请求数据,例子如图12。
图12 host方法例子
上面的代码中this.req是http.IncomingMessage实例,包含了http请求信息。Response中包含了处理请求响应的操作。例如设置响应状态信息,如图13
图13 status
其中this.res指http.ServerResponse对象实例。
到此处,图1中三行代码的背后逻辑已分析完成。