koa源碼

寫在前面

本文將會你們來看下koa的源碼,固然本文須要你們瞭解koa的中間件機制,若是你們以前沒有了解過其實現原理,能夠關注下這篇文章
koa的源碼很是的精簡,與express不一樣,koa只是爲開發者搭起了一個架子,沒有任何的功能,包括路由,所有由中間件實現;下面就來看下koa的實現:node

koa

建立應用時,通常都會利用app.listen指定一個端口號,這個方法的本質就是http.createServergit

listen() {
    debug('listen');
    const server = http.createServer(this.callback());
    return server.listen.apply(server, arguments);
}

最爲關鍵的就是這個callback的實現:github

clipboard.png

callback() {
    const fn = compose(this.middleware);

    if (!this.listeners('error').length) this.on('error', this.onerror);

    const handleRequest = (req, res) => {
        res.statusCode = 404;
        const ctx = this.createContext(req, res);
        const onerror = err => ctx.onerror(err);
        const handleResponse = () => respond(ctx);
        onFinished(res, onerror);
        return fn(ctx).then(handleResponse).catch(onerror);
    };

    return handleRequest;
}

須要注意下面幾點:express

  • onFinished(res, onerror),應對的是返回的bodyStream的狀況,爲其添加一個finished事件。npm

  • respond()根據ctxstatus,body,method來決定如何響應此次請求:api

    • status204,304,不須要有響應體,res.end()就好cookie

    • methodHEADHEAD的意義是不請求資源內容可是須要了解資源狀況,因此只須要請求頭,指定了資源lengthres.end()就好app

    • 加入body爲空,則bodystatuses包中status對應的文字描述,如404 => Not Foundkoa

context對象

koarequest對象response封裝成了一個對象,提供了一些別名,具體能夠參見context對象,例如:當訪問ctx.url實則是訪問的ctx.request.url。具體的實現利用了tj寫的delegates這個npm包來對context對象添加屬性,koa中利用了其中三個api:socket

  • method:添加方法引用

  • getter:利用__defineGetter__,添加getter屬性

  • access:添加gettersetter

對於context建立的代碼:

createContext(req, res) {
    const context = Object.create(this.context);
    const request = context.request = Object.create(this.request);
    const response = context.response = Object.create(this.response);
    context.app = request.app = response.app = this;
    context.req = request.req = response.req = req;
    context.res = request.res = response.res = res;
    request.ctx = response.ctx = context;
    request.response = response;
    response.request = request;
    context.originalUrl = request.originalUrl = req.url;
    context.cookies = new Cookies(req, res, {
      keys: this.keys,
      secure: request.secure
    });
    request.ip = request.ips[0] || req.socket.remoteAddress || '';
    context.accept = request.accept = accepts(req);
    context.state = {};
    return context;
  }

函數的參數req, res爲node自己的對象,requestresponse分別是對於reqres的封裝,讀取ctx.url的過程以下:

clipboard.png

context就是一個頂層對象,koa中,全部的屬性和操做基本會基於這個對象,這個對象的組成以下圖:

clipboard.png

寫在最後

我的感受koa就像是一個架子,提供了基礎的方法和屬性,如ctx.redirect等,具體的功能主要利用中間件來實現,與express相比,koa去除內置路由,views等,變得更加的輕量;固然我認爲更加劇要的是避免了層層回調的出現。以上內容若有出錯,歡迎你們指出。

相關文章
相關標籤/搜索