Express框架Router?Route?Layer對象使用示例詳解
引言
這使用倒敘的方式: 將 Layer 放在最前面講解,然后是 Route 路由項目,最后是 Router 路由器。
Layer
Layer 是什么? Express 中最小的存儲單元,存儲的重要內(nèi)容包括 handle 也就是 fn、path 等路徑。fn 就是中間件處理函數(shù)。重要的是 route 中能匹配:
module.exports = Layer;
function Layer(path, options, fn) {
if (!(this instanceof Layer)) {
return new Layer(path, options, fn);
}
var opts = options || {};
this.handle = fn;
this.name = fn.name || '<anonymous>';
this.params = undefined;
this.path = undefined;
this.regexp = pathRegexp(path, this.keys = [], opts);
this.regexp.fast_star = path === '*'
this.regexp.fast_slash = path === '/' && opts.end === false
}
Layer.prototype.handle_error = function handle_error(error, req, res, next) {}
Layer.prototype.handle_request = function handle(req, res, next) {}
Layer.prototype.match = function match(path) {} // 返回 boolean
看看哪些的內(nèi)容實例化了 Layer 的構造函數(shù)。Layer 的最主要的作用就是,被路由匹配到,然后取出 handle 函數(shù)最后調(diào)用,消費 handle 函數(shù)。
- Route
一個 Route 的棧 stack 中,可以存放多個 Layer。
Route.prototype.all = function all() {
/**/
var layer = Layer('/', {}, handle);
/**/
}
Route.prototype[method] = function(){
/**/
var layer = Layer('/', {}, handle);
/**/
}
- Router 中
proto.route = function route(path) {
// ***
var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: this.strict,
end: true
}, route.dispatch.bind(route));
// ***
this.stack.push(layer);
};
proto.use = function use(fn) {
var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: false,
end: false
}, fn);
this.stack.push(layer);
}
在 Router 中的 route 和 use 函數(shù),使用 Layer 構造函數(shù)實例化 layer, 然后將 layer 壓到 stack 中保存卡里,方便以后匹配。
- layer 的匹配方法
function matchLayer(layer, path) {
try {
return layer.match(path);
} catch (err) {
return err;
}
}
從上面的代碼中知道,layer 對象的 match 方法,根據(jù)路徑進行匹配, match 返回 boolean. 在匹配的時候主要處理了兩個屬性:
this.params = undefined; this.path = undefined;
接下來看 matchLayer 函數(shù), matchLayer 調(diào)用在 Router.handle 函數(shù)的 next 函數(shù)中。
Route
module.exports = Route;
function Route(path) {
this.path = path;
this.stack = [];
this.methods = {};
}
Route.prototype._handles_method = function _handles_method(method) {/*...*/}
Route.prototype._options = function _options() {/*...*/}
Route.prototype.dispatch = function dispatch(req, res, done) {/*...*/}
Route.prototype.all = function all() {/*...*/}
// 擴展 methods 包中的方法
Router
Router 就是 proto
var proto = module.exports = function(options) {/*...*/}
proto.param = function param(name, fn) {/*...*/}
proto.handle = function handle(req, res, out) {/*...*/}
proto.process_params = function process_params(layer, called, req, res, done) {/*...*/}
proto.use = function use(fn) {/*...*/}
proto.route = function route(path) {/*...*/}
// 擴展 methods + all 上所有的方法
注意: Router.handle 函數(shù).
var stack = self.stack;
while (match !== true && idx < stack.length) {/*...*/}
在 while 循環(huán)中,使用 idx 中取出 layer 和 path然后交給 matchLayer 函數(shù), 得到匹配結果。如果調(diào)用的內(nèi)容正常:
layer.handle_request(req, res, next) // 最終會得到中間件的處理函數(shù)
接下來盤點, Router/Route/Layer 的常用方法
方法統(tǒng)計
- Router
| Router 方法 | 說明 |
|---|---|
| Router param | 參數(shù) |
| Router handle | 處理函數(shù) |
| Router process_params | 處理參數(shù) |
| Router use | 中間件 |
| Router route | 路由 |
| Router [methods]/all | 各種方法 |
- Route
| Route 方法 | 說明 |
|---|---|
| Route _handles_method | 私有處理函數(shù) |
| Route _options | 私有選項 |
| Route dispatch | 派發(fā)請求和響應 |
| Route all | 各種方法 |
| Route [methods] | 各種方法 |
- Layer
| Layer 方法 | 說明 |
|---|---|
| Layer handle_error | 處理錯誤 |
| Layer handle_request | 處理請求 |
| Layer match | 根據(jù)路徑匹配路由并返回 boolean |
看 Router 和 Route 有相同的方法: all/[methods]。使用 Router.route 的方法通過 path 方法關聯(lián)。同時 咋 Router.route 中實例化 Layer ,然后將 layer 保存在 Router 的 stack 中。
兩個 stack
從上面的分析中,知道了 Router 中有 stack,Route 中也有 stack, 在 stack 中添加內(nèi)容(也就是 Layer)一般都是與路由和中間件相關。
- Router 的 use 方法中,包含了實例化 Layer, 并存儲在 Router 級別的 stack 中。
- Router 的 route 中,實例化了 Layer, 并存儲在 Router 級別的 stack 中。
- Router 的 [methods]/all 方法中,調(diào)用了 route 方法,自然也存儲了 stack
取出 stack 中 layer
取出 Layer 發(fā)生在 Route 的 dispatch 函數(shù) 的 next 函數(shù)中,此時需要調(diào)用 layer 中匹配到的參數(shù)。
從 Router 到 layer 的路徑
- Router 是被 express 單獨的輸出出去的。
- Router 實例化之后,可以調(diào)用 use/[methods] 實例化 Layer 并保存 stack 中,當然也可調(diào)用 Router.route 方法。
Router.route 方法中的 dispatch
var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: this.strict,
end: true
}, route.dispatch.bind(route));
route.dispatch 在此處 bind 綁定,此時作為 Layer 構造函數(shù)的第三個參數(shù),保存為 handle, 最后會被拿出調(diào)用。此時就進入了 next 函數(shù)調(diào)用階段。
next 函數(shù)
next 函數(shù)是 Express 中間件的基礎,dispatch 函數(shù)從 當前的 stack 中拿出 layer 的實際情況調(diào)用 layer 不同的方法。
if (layer.method && layer.method !== method) {
next(err)
}
當 layer 中的方法或者等于但當前的方法時,調(diào)用自己,此時 next 函數(shù)發(fā)生了遞歸。否則進入 handle 相關方法處理請求和處理錯階段,此時 next 方法發(fā)生了遞歸調(diào)用。
小結
- Router -> Route -> Layer
- Router -> use -> Layer
- Router 和 Route 都有自己 stack 存儲 layer
- next 函數(shù)在 Route 的 dispatch 被執(zhí)行,并在 layer 相關屬性中發(fā)生 next 函數(shù)的遞歸,實現(xiàn)了 Express 的中間件。
以上就是Express框架Router Route Layer對象使用示例詳解的詳細內(nèi)容,更多關于Express使用Router Route Layer的資料請關注腳本之家其它相關文章!
相關文章
神奇的代碼 通殺各種網(wǎng)站-可隨意修改復制頁面內(nèi)容
在瀏覽器地址欄輸入這一行代碼,然后回車,就發(fā)現(xiàn)整個頁面都可以隨意編輯了。僅僅是一行很短的代碼。2008-07-07
javascript中獲取元素標簽中間的內(nèi)容的實現(xiàn)方法
下面小編就為大家?guī)硪黄猨avascript中獲取元素標簽中間的內(nèi)容的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10
純JavaScript基于notie.js插件實現(xiàn)消息提示特效
這篇文章主要介紹了純JavaScript基于notie.js插件實現(xiàn)消息提示特效,可以制作Alert提示框,確認框和帶輸入的消息框,感興趣的小伙伴們可以參考一下2016-01-01
通過Tabs方法基于easyUI+bootstrap制作工作站
本教程給大家介紹如何制作easyUI+bootstrap工作站,主要學習tabs方法,本文介紹非常詳細,具有參考借鑒價值,需要的朋友參考下吧2016-03-03

