国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

探討Express Router & Route

oysun / 2383人閱讀

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

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

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

//安裝依賴
npm install

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

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

接下來我們通過:

npm start 

啟動程序后,訪問127.0.0.1:3000,就能訪問到express的頁面了。

接下來通過研究源碼,來探討express路由原理的實現(xiàn)。

路由

我們通過查看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的路由大概實現(xiàn) 定義一份路由規(guī)則文件,再通過app.use()或者app[METHOD]來建立路由規(guī)則訪問聯(lián)系,雖然兩者的結(jié)果一樣,但是存在本質(zhì)上的區(qū)別。

下圖是主要涉及的幾個文件:

接下來我們通過源碼首先看看app.use()具體是一個什么樣實現(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,并且通過lazyrouter()方法實例router類,并且全局只存在一個router實例對象,最終調(diào)用router.use()方法。

接著,我們到lib/router/index.js 看router.use方法的實現(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;
};

通過對比app.use方法,router.use前半部分處理相同,但后面實例化一個Layer類,并且丟進stack里。

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

相同點:

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

不同點:

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

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

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

app[METHOD]

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

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;
    };
});

可以看出,代碼里做了一個app.get方法的判斷處理,get方法只有一個參數(shù)時,是獲取app的本地變量,后面還是實例化router對象,并且用router上的route方法放回的對象去調(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里有一個實例化的layer,且放在stack里,與Router的layer不同的是,Route的沒有l(wèi)ayer.route且layer.method存放http方法。

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

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

完整的Router邏輯過程,如圖:

總結(jié)

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

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

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

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/93337.html

相關(guān)文章

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

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

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

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

    laznrbfe 評論0 收藏0
  • express 的 middleware 設(shè)計

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

    zollero 評論0 收藏0
  • 筆記:解讀express 4.x源碼

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

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

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

    Steven 評論0 收藏0

發(fā)表評論

0條評論

oysun

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<