成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

探討Express Router & Route

oysun / 2425人閱讀

摘要:接下來(lái)通過(guò)研究源碼,來(lái)探討路由原理的實(shí)現(xiàn)。類保存和一些數(shù)據(jù)信息相同點(diǎn)都是存放掛載路徑用來(lái)判斷是否是路由中間件。放在里的路由中間件,通過(guò)指向,與相關(guān)聯(lián)起來(lái)

Express
基于 Node.js 平臺(tái),快速、開放、極簡(jiǎn)的 web 開發(fā)框架
安裝
//應(yīng)用生成器工具
npm install express-generator -g

//創(chuàng)建express應(yīng)用包
express app

//安裝依賴
npm install

成功生成后,會(huì)產(chǎn)生以下的目錄和文件:

|---bin
|---node_module
|---public
|---routes
|---view
|---app.js
|---package.json

接下來(lái)我們通過(guò):

npm start 

啟動(dòng)程序后,訪問(wèn)127.0.0.1:3000,就能訪問(wèn)到express的頁(yè)面了。

接下來(lái)通過(guò)研究源碼,來(lái)探討express路由原理的實(shí)現(xiàn)。

路由

我們通過(guò)查看app.jsindex.js文件:

app.js

var index = require("./routes/index");

app.use("/", index);

//或
app.get("/", index);

routes/index.js

var express = require("express");
var router = express.Router();

router.get("/", function(req, res, next) {
  res.render("index", { title: "Express" });
});

可以看出,express的路由大概實(shí)現(xiàn) 定義一份路由規(guī)則文件,再通過(guò)app.use()或者app[METHOD]來(lái)建立路由規(guī)則訪問(wèn)聯(lián)系,雖然兩者的結(jié)果一樣,但是存在本質(zhì)上的區(qū)別。

下圖是主要涉及的幾個(gè)文件:

接下來(lái)我們通過(guò)源碼首先看看app.use()具體是一個(gè)什么樣實(shí)現(xiàn)思路。

app.use

我們打開node_module里的express文件夾。打開lib/application.js文件。

app.use = function use(fn) {
    var offset = 0;
    var path = "/";

    // default path to "/"
    // disambiguate app.use([fn])
    if (typeof fn !== "function") {
        var arg = fn;

        while (Array.isArray(arg) && arg.length !== 0) {
            arg = arg[0];
        }

        // first arg is the path
        if (typeof arg !== "function") {
            offset = 1;
            path = fn;
        }
    }

    var fns = flatten(slice.call(arguments, offset));

    if (fns.length === 0) {
        throw new TypeError("app.use() requires middleware functions");
    }

    // setup router
    this.lazyrouter();
    var router = this._router;

    fns.forEach(function(fn) {
        // non-express app
        if (!fn || !fn.handle || !fn.set) {
            return router.use(path, fn);
        }

        debug(".use app under %s", path);
        fn.mountpath = path;
        fn.parent = this;

        // restore .app property on req and res
        router.use(path, function mounted_app(req, res, next) {
            var orig = req.app;
            fn.handle(req, res, function(err) {
                setPrototypeOf(req, orig.request)
                setPrototypeOf(res, orig.response)
                next(err);
            });
        });

        // mounted an app
        fn.emit("mount", this);
    }, this);

    return this;
};

看到use里部分的代碼,開始做了判斷處理use掛載的是路徑還是function,并且通過(guò)lazyrouter()方法實(shí)例router類,并且全局只存在一個(gè)router實(shí)例對(duì)象,最終調(diào)用router.use()方法。

接著,我們到lib/router/index.js 看router.use方法的實(shí)現(xiàn):

proto.use = function use(fn) {
  var offset = 0;
  var path = "/";

  // default path to "/"
  // disambiguate router.use([fn])
  if (typeof fn !== "function") {
    var arg = fn;

    while (Array.isArray(arg) && arg.length !== 0) {
      arg = arg[0];
    }

    // first arg is the path
    if (typeof arg !== "function") {
      offset = 1;
      path = fn;
    }
  }

  var callbacks = flatten(slice.call(arguments, offset));

  if (callbacks.length === 0) {
    throw new TypeError("Router.use() requires middleware functions");
  }

  for (var i = 0; i < callbacks.length; i++) {
    var fn = callbacks[i];

    if (typeof fn !== "function") {
      throw new TypeError("Router.use() requires middleware function but got a " + gettype(fn));
    }

    // add the middleware
    debug("use %o %s", path, fn.name || "")

    var layer = new Layer(path, {
      sensitive: this.caseSensitive,
      strict: false,
      end: false
    }, fn);

    layer.route = undefined;

    this.stack.push(layer);
  }

  return this;
};

通過(guò)對(duì)比app.use方法,router.use前半部分處理相同,但后面實(shí)例化一個(gè)Layer類,并且丟進(jìn)stack里。

Layer類保存Router和Route一些數(shù)據(jù)信息:

相同點(diǎn):

path都是存放掛載路徑,options.end用來(lái)判斷是否是路由中間件。

不同點(diǎn):

Router和Route的區(qū)別是一個(gè)是添非路由中間件,另一個(gè)是添加路由中間件。

他們的layer.route指向也不一樣,一個(gè)指向undefined,另一個(gè)沒有route屬性。

文章進(jìn)行到一半,我們小總結(jié)一下,app.use()方法是用來(lái)添加非路由中間件的,最終是調(diào)用router實(shí)例方法,會(huì)實(shí)例劃一個(gè)Layer類對(duì)象用于存放數(shù)據(jù),并且把layer對(duì)象push進(jìn)router.stack里,全局只有一個(gè)router。

app[METHOD]

我們通過(guò)源碼去探討路由中間件app[METHOD]是一個(gè)怎樣的原理:

app.jsapp.use("",index)改成app.get("",index).

application.js:

methods.forEach(function(method) {
    app[method] = function(path) {
        if (method === "get" && arguments.length === 1) {
            // app.get(setting)
            return this.set(path);
        }

        this.lazyrouter();

        var route = this._router.route(path);
        route[method].apply(route, slice.call(arguments, 1));
        return this;
    };
});

可以看出,代碼里做了一個(gè)app.get方法的判斷處理,get方法只有一個(gè)參數(shù)時(shí),是獲取app的本地變量,后面還是實(shí)例化router對(duì)象,并且用router上的route方法放回的對(duì)象去調(diào)用Route類上的route[METHOD].

/lib/router/route.js

methods.forEach(function(method){
  Route.prototype[method] = function(){
    var handles = flatten(slice.call(arguments));

    for (var i = 0; i < handles.length; i++) {
      var handle = handles[i];

      if (typeof handle !== "function") {
        var type = toString.call(handle);
        var msg = "Route." + method + "() requires callback functions but got a " + type;
        throw new Error(msg);
      }

      debug("%s %o", method, this.path)

      var layer = Layer("/", {}, handle);
      layer.method = method;

      this.methods[method] = true;
      this.stack.push(layer);
    }

    return this;
  };
});

在route里有一個(gè)實(shí)例化的layer,且放在stack里,與Router的layer不同的是,Route的沒有l(wèi)ayer.route且layer.method存放http方法。

到這里,我們大概可以總結(jié)下路由中間件和非路由中間件的聯(lián)系,如下圖:

app初始化時(shí),會(huì)push兩個(gè)方法(init,query)進(jìn)router.stack里。我們可以通過(guò)app.use往app添加非路由中間件,也可以通過(guò)app[METHOD]添加路由中間件,同樣是push layer實(shí)例對(duì)象,但route是指向Route實(shí)例化的對(duì)象。

完整的Router邏輯過(guò)程,如圖:

總結(jié)

express中添加中間件方法有app.use和app[METHOD],當(dāng)然還有內(nèi)置的Router類,app.use用來(lái)添加非路由中間件,app[METHOD]用來(lái)添加路由中間件。

Layer類封裝中間的path和handle(fns的處理)

Router和Route都有對(duì)應(yīng)的stack,但是Route在整個(gè)app中只有一個(gè),而Route可以又多個(gè)。放在Router
stack里的路由中間件,通過(guò)Layer.route指向Route,與Route stack相關(guān)聯(lián)起來(lái)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93337.html

相關(guān)文章

  • Sails.js 內(nèi)存暴漲 &amp; 源碼分析

    摘要:是下的一個(gè)優(yōu)秀的框架,但是使用后,在流量增長(zhǎng)時(shí),進(jìn)程有時(shí)突然內(nèi)存暴漲保持高占用。如果是內(nèi)存泄露引起的,則需要細(xì)心檢查代碼,確定變量能正?;厥?。每個(gè)對(duì)象有自己產(chǎn)生的內(nèi)存。譯注但是大對(duì)象內(nèi)存區(qū)本身不是可執(zhí)行的內(nèi)存區(qū)。 Sails.js 是 node 下的一個(gè)優(yōu)秀的 MVC 框架,但是使用 Sails 后,在流量增長(zhǎng)時(shí), node 進(jìn)程有時(shí)突然內(nèi)存暴漲、保持高占用。經(jīng)過(guò)翻閱源碼后,發(fā)現(xiàn)這個(gè)問(wèn)...

    antz 評(píng)論0 收藏0
  • Express源碼學(xué)習(xí)-路由篇

    摘要:框架核心特性路由定義了路由表用于執(zhí)行不同的請(qǐng)求動(dòng)作。中間件可以設(shè)置中間件來(lái)響應(yīng)請(qǐng)求。注冊(cè)一個(gè)請(qǐng)求路由結(jié)束響應(yīng)開啟監(jiān)聽端口執(zhí)行上面代碼是一種實(shí)用工具,將為您的源的任何變化并自動(dòng)重啟服務(wù)器監(jiān)控。 Express 簡(jiǎn)介 Express 是一個(gè)簡(jiǎn)潔而靈活的 node.js Web應(yīng)用框架, 提供了一系列強(qiáng)大特性幫助你創(chuàng)建各種 Web 應(yīng)用,和豐富的 HTTP 工具。使用 Express 可以快...

    laznrbfe 評(píng)論0 收藏0
  • express 的 middleware 設(shè)計(jì)

    摘要:入口文件在文件夾下的,其向外界暴露了一些方法。方法也是從中繼承的。入口文件很清晰,主要是完成方法的暴露以及的一些初始化操作。下一篇寫寫路由的實(shí)現(xiàn)。 還沒用express寫過(guò)server,先把部分源碼擼了一遍,各位大神求輕拍。 express入口文件在lib文件夾下的express.js,其向外界暴露了一些方法。 最主要的(express.js 第36-47行): function cr...

    zollero 評(píng)論0 收藏0
  • 筆記:解讀express 4.x源碼

    摘要:載入了框架,我們來(lái)看源代碼中的。函數(shù)函數(shù)代碼如下代碼的開始定義了一個(gè)函數(shù),函數(shù)有形參,,為回調(diào)函數(shù)。相應(yīng)的,等同于繼承,從而讓有了事件處理的能力。 此為裁剪過(guò)的筆記版本。 原文在此:https://segmentfault.com/a/11...原文在此: https://cnodejs.org/topic/574... 感謝@YiQi ,@leijianning 帶來(lái)的好文章。我稍作...

    jzman 評(píng)論0 收藏0
  • express 源碼閱讀(全)

    摘要:每個(gè)請(qǐng)求都會(huì)對(duì)應(yīng)一個(gè)響應(yīng)。一個(gè)響應(yīng)主要包括狀態(tài)行響應(yīng)頭消息體,將常用的數(shù)據(jù)封裝為類,在上面的代碼中就是該類的一個(gè)對(duì)象。執(zhí)行測(cè)試用例,報(bào)錯(cuò),提示不存在。目前在中,一個(gè)路由是由三個(gè)部分構(gòu)成路徑方法和處理函數(shù)。 1. 簡(jiǎn)介 這篇文章主要的目的是分析理解express的源碼,網(wǎng)絡(luò)上關(guān)于源碼的分析已經(jīng)數(shù)不勝數(shù),這篇文章準(zhǔn)備另辟蹊徑,仿制一個(gè)express的輪子,通過(guò)測(cè)試驅(qū)動(dòng)的開發(fā)方式不斷迭代,正...

    Steven 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

oysun

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<