lib/router/layer.js
module.exports = Layer;
//Layer构造函数,一个Layer可以属于router,也可以属于Route
//当调用router的route方法时,Layer作为Route对象的中间层,它的path与创建的Route的path一样,它的handle为Route的dispatch方法
//当调用router的use方法时,Layer的handle为use添加的中间件方法,可能是一个router对象、也可能是一个标准的中间件方法
//当属于Route时,代表一个使用all、get、post方法添加的路由处理方法,此时Layer是有method的,但是其path为/,可以做方法匹配,但是不做路径匹配
function Layer(path, options, fn) {
//确保作为构造函数调用
if (!(this instanceof Layer)) {
return new Layer(path, options, fn);
}
debug('new %o', path)
var opts = options || {};
//设置处理函数,可能为中间件,此时可能为普通中间件函数、Router对象、express实例的包装函数
//可能为指定http方法的处理函数、Route的dispatch方法
//一个handle只可能处理请求或者err,必须是标准的请求处理函数req、res、next或者标准的错误处理函数err、req、res、next
this.handle = fn;
//函数名或者匿名函数,因为Router本身就是匿名函数
this.name = fn.name || '<anonymous>';
this.params = undefined;
//路径,属于Router时,代表挂载的中间件路径
//属于Route时,为/
this.path = undefined;
//正则
this.regexp = pathRegexp(path, this.keys = [], opts);
// 快速匹配
//路径是否为*,代表匹配所有路径
this.regexp.fast_star = path === '*'
//path为/,代表匹配根路径
this.regexp.fast_slash = path === '/' && opts.end === false
}
//错误处理函数
Layer.prototype.handle_error = function handle_error(error, req, res, next) {
//内部处理函数还是handle
var fn = this.handle;
//函数的参数不是四个,err、req、res、next,即不是标准的express错误处理函数,继续向下传递
if (fn.length !== 4) {
return next(error);
}
try {
fn(error, req, res, next);
} catch (err) {
next(err);
}
};
//请求处理函数
Layer.prototype.handle_request = function handle(req, res, next) {
var fn = this.handle;
//如果参数多于三个,说明不是标准的请求处理函数
if (fn.length > 3) {
return next();
}
try {
fn(req, res, next);
} catch (err) {
next(err);
}
};
//Layer是否匹配指定路径
Layer.prototype.match = function match(path) {
var match
if (path != null) {
//当Layer属于一个Route时,path为/, /肯定匹配所有路径开始的/,因为每个路径开始都是/
if (this.regexp.fast_slash) {
//此时路径参数为空,因为Layer匹配部分只有一个/其他部分另外处理
this.params = {}
//path为空
this.path = ''
return true
}
//当Layer路径为*代表匹配所有路由,此时匹配部分为参数path的全部
if (this.regexp.fast_star) {
//路径参数
this.params = {'0': decode_param(path)}
//路径
this.path = path
return true
}
//其他普通情况,执行正则匹配
match = this.regexp.exec(path)
}
//没有匹配项
if (!match) {
//路径与路径参数都为空
this.params = undefined;
this.path = undefined;
return false;
}
//路径为第一个匹配项
this.params = {};
this.path = match[0]
//路径参数
var keys = this.keys;
var params = this.params;
//遍历匹配结果数组,从下标1开始,因为0已经给了path
for (var i = 1; i < match.length; i++) {
var key = keys[i - 1];
//获取路径参数名
var prop = key.name;
//解码匹配项为路径参数值
var val = decode_param(match[i])
if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
//将路径参数赋值给params属性
params[prop] = val;
}
}
return true;
};
//解码路径参数值
function decode_param(val) {
//不是字符串或者长度为0,直接返回
if (typeof val !== 'string' || val.length === 0) {
return val;
}
try {
//url组件解码
return decodeURIComponent(val);
} catch (err) {
if (err instanceof URIError) {
err.message = 'Failed to decode param \'' + val + '\'';
err.status = err.statusCode = 400;
}
throw err;
}
}