brunoyang/blog

koa源码分析(一) - application.js

brunoyang opened this issue · 4 comments

本文分为四个部分,分别对应源码的四个文件。

仓库:https://github.com/koajs/koa

官网:http://koajs.com/

官方介绍:Koa is a new web framework designed by the team behind Express, which aims to be a smaller, more expressive, and more robust foundation for web applications and APIs. Through leveraging generators Koa allows you to ditch callbacks and greatly increase error-handling. Koa does not bundle any middleware within core, and provides an elegant suite of methods that make writing servers fast and enjoyable.

本文根据koa@1.0.0撰写。

依赖

  • debug:debug源码分析
  • compose_es7:与co.wrap相似,不过能够接受 async/await 函数;
  • onFinished:捕捉finish或error事件,并根据第二个参数执行回调;
  • compose:compose_es7的简化版,只接受generator;
  • isJSON:顾名思义,判断传入参数是否为JSON;
  • statuses:将http码分为三类,redirect、empty以及retry,然后根据传入的http来判断属于哪一类;
  • accepts:根据req的内容判断(content negotiation)字段,如accept,Accept-Encoding,Accept-Language等字段对这些字段进行格式化,方便后续处理;
  • only:只返回在传入参数里所包含的字段;
  • co:co源码解析

源码解析

Application

koi暴露了Application对象作为入口,Application的几个属性挑重要的讲:middlewarecontextrequestresponse会在后续文章里讲到。

middleware

middleware是一个数组,在这里特称为中间件数组,数组元素要求是generator函数。当然开启了experimental就可以用async/await了。

middleware数组是如何工作的可以参考下图

middleware 数组

context

http请求和相应进行包装,得到包含requestresponse的对象,对象所具体包含的内容在下面会有写到。

Application.prototype

Applicationn的prototype继承自event.Emitter的prototype,并挂载了多个方法。

listen

这是http.createServer(app.callback()).listen(...)的简写,重要的是当中的callback函数。

callback函数的第一行就是将response函数作为了middleware数组的第一个元素,所以我们再来看一下response函数。

response函数的第一句,就是个yield *next,也就是说在req进入中间件数组时response函数不作处理。那什么时候处理呢?看一下上面这张图,可以看到,response函数在之后的所有中间件都执行完成后,对res做最后一步的处理。

middleware数组放入compose后,会得到一个generator函数,这个generator函数的效果相当于是将多个中间件组合成一个,来让co可以按顺序执行。最后,传入ctx,完成一次http请求。

createContext

ctx从哪来的呢,是由createContext函数创建的。返回的结果形如下面的代码。requestresponsekoa生成的对象,resreqnode原生的http对象,当需要访问原生对象时,可以通过this.res来访问到,但并不推荐这样做,推荐直接访问request对象。

{
    request: {
        url: '/',
        method: 'GET',
        req: <origin node >
        ...
    },
    response: {

    }
    app: {
        subdomainOffset: 2,
        env: 'development'
    },
    originalUrl: '/',
    req: '<original node req>',
    res: '<original node res>',
    socket: '<original node socket>'
}

inspect/toJSON

返回配置的参数subdomainOffsetenv

2.0 快出来了,有时间也分析一下吧

@camsong ok 这周末

前来拜读

mark