日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

探讨Express Router Route

發布時間:2024/4/14 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 探讨Express Router Route 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Express

基于 Node.js 平臺,快速、開放、極簡的 web 開發框架

安裝

//應用生成器工具 npm install express-generator -g//創建express應用包 express app//安裝依賴 npm install

成功生成后,會產生以下的目錄和文件:

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

接下來我們通過:

npm start

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

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

路由

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

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

接下來我們通過源碼首先看看app.use()具體是一個什么樣實現思路。

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 pathif (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 routerthis.lazyrouter();var router = this._router;fns.forEach(function(fn) {// non-express appif (!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 resrouter.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 appfn.emit('mount', this);}, this);return this; };

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

接著,我們到lib/router/index.js 看router.use方法的實現:

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 pathif (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 middlewaredebug('use %o %s', path, fn.name || '<anonymous>')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一些數據信息:

相同點:

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

不同點:

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

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

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

app[METHOD]

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

在app.js把app.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方法只有一個參數時,是獲取app的本地變量,后面還是實例化router對象,并且用router上的route方法放回的對象去調用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的沒有layer.route且layer.method存放http方法。

到這里,我們大概可以總結下路由中間件和非路由中間件的聯系,如下圖:

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

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

總結

  • express中添加中間件方法有app.use和app[METHOD],當然還有內置的Router類,app.use用來添加非路由中間件,app[METHOD]用來添加路由中間件。
  • Layer類封裝中間的path和handle(fns的處理)
  • Router和Route都有對應的stack,但是Route在整個app中只有一個,而Route可以又多個。放在Router
    stack里的路由中間件,通過Layer.route指向Route,與Route stack相關聯起來
  • 總結

    以上是生活随笔為你收集整理的探讨Express Router Route的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。