这运用倒叙的方式: 将 Layer 放在最前面讲解,然后是 Route 路由项目,最后是 Router 路由器。
Layer
Layer 是什么? Express 中最小的存储单元,存储的重要内容包括 handle 也便是 fn
、path
等途径。fn 便是中间件处理函数。重要的是 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
看看哪些的内容实例化了 Layer 的结构函数。Layer 的最首要的作用便是,被路由匹配到,然后取出 handle 函数最后调用,消费 handle 函数。
- 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 函数,运用 Layer 结构函数实例化 layer, 然后将 layer 压到 stack 中保存卡里,方便以后匹配。
- layer 的匹配办法
function matchLayer(layer, path) {
try {
return layer.match(path);
} catch (err) {
return err;
}
}
从上面的代码中知道,layer 对象的 match 办法,依据途径进行匹配, match 回来 boolean. 在匹配的时候首要处理了两个属性:
this.params = undefined;
this.path = undefined;
接下来看 matchLayer 函数, matchLayer 调用在 Router.handle 函数的 next 函数中。
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 函数.
var stack = self.stack;
while (match !== true && idx < stack.length) {/*...*/}
在 while 循环中,运用 idx 中取出 layer 和 path然后交给 matchLayer 函数, 得到匹配成果。如果调用的内容正常:
layer.handle_request(req, res, next) // 终究会得到中间件的处理函数
接下来盘点, Router/Route/Layer 的常用办法
办法计算
- Router
Router 办法 | 说明 |
---|---|
Router param
|
参数 |
Router handle
|
处理函数 |
Router process_params
|
处理参数 |
Router use
|
中间件 |
Router route
|
路由 |
Router [methods]/all
|
各种办法 |
- Route
Route 办法 | 说明 |
---|---|
Route _handles_method
|
私有处理函数 |
Route _options
|
私有选项 |
Route dispatch
|
派发恳求和响应 |
Route all
|
各种办法 |
Route [methods]
|
各种办法 |
- Layer
Layer 办法 | 说明 |
---|---|
Layer handle_error
|
处理错误 |
Layer handle_request
|
处理恳求 |
Layer match
|
依据途径匹配路由并回来 boolean |
看 Router 和 Route 有相同的办法: all/[methods]
。运用 Router.route 的办法经过 path 办法关联。一起 咋 Router.route 中实例化 Layer ,然后将 layer 保存在 Router 的 stack 中。
两个 stack
从上面的分析中,知道了 Router 中有 stack,Route 中也有 stack, 在 stack 中添加内容(也便是 Layer)一般都是与路由和中间件相关。
- Router 的 use 办法中,包含了实例化 Layer, 并存储在 Router 等级的 stack 中。
- Router 的 route 中,实例化了 Layer, 并存储在 Router 等级的 stack 中。
- Router 的
[methods]/all
办法中,调用了 route 办法,自然也存储了 stack
取出 stack 中 layer
取出 Layer 发生在 Route 的 dispatch 函数 的 next 函数中,此刻需要调用 layer 中匹配到的参数。
从 Router 到 layer 的途径
- Router 是被 express 单独的输出出去的。
- Router 实例化之后,能够调用
use/[methods]
实例化 Layer 并保存 stack 中,当然也可调用 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 结构函数的第三个参数,保存为 handle, 最后会被拿出调用。此刻就进入了 next 函数调用阶段。
next 函数
next 函数是 Express 中间件的根底,dispatch 函数从 当前的 stack 中拿出 layer 的实际情况调用 layer 不同的办法。
if (layer.method && layer.method !== method) {
next(err)
}
当 layer 中的办法或许等于但当前的办法时,调用自己,此刻 next 函数发生了递归。不然进入 handle 相关办法处理恳求和处理错阶段,此刻 next 办法发生了递归调用。
小结
- Router -> Route -> Layer
- Router -> use -> Layer
- Router 和 Route 都有自己 stack 存储 layer
- next 函数在 Route 的 dispatch 被执行,并在 layer 相关属性中发生 next 函数的递归,完成了 Express 的中间件。