Router模块
1.加载模块执行代码:
methods.forEach(function(method){ //method是http协议的各种请求方法,如:get,put,headee,post Route.prototype[method] = function(){ ....为method的各种方法构造一个Layer,并且放入stack数组中 }; });
//其实router.all()的功能和methods的功能差不多。
methods方法包含有:
function getBasicNodeMethods() { return [ 'get', 'post', 'put', 'head', 'delete', 'options', 'trace', 'copy', 'lock', 'mkcol', 'move', 'purge', 'propfind', 'proppatch', 'unlock', 'report', 'mkactivity', 'checkout', 'merge', 'm-search', 'notify', 'subscribe', 'unsubscribe', 'patch', 'search', 'connect' ]; }
2.构造函数
function Route(path) { //三个成员, 路由的路径,方法对象。和储存对应的请求处理函数 this.path = path; this.stack = []; debug('new %s', path); // route handlers for various http methods this.methods = {}; }
3.原型对象上方法
Route.prototype ={ /*返回boolean类型,判断router是否支持给定的method方法,有个特殊情况:当method时head,并且Router不支持head请求时,method改成get*/ _handles_method:_handles_method(method), /*返回一个route所支持的HTTP请求的数组,特殊情况:如果请求时方法get支持,而head不支持,那么head也应该改成true*/ _options:_options(), //遍历该Route的stack(不是Router)中所有的Layer,依次执行。递归来解决遍历,要注意的是:在fn执行错误之后抛出err,如果这个err === "route",那么结束遍历,否则继续,执行下一个fn, dispatch:function dispatch(req, res, done), //支持所有http请求,而且this.method._all为true。 _all:function(){ //layer.method = undefined; this.methods._all = true; } }
dispatch是在router.route方法中,初始化layer的时候绑定到Layer.handler上的,解析下dispatch代码:
next(); function next(err) { //执行layer.handle抛出route就不需要再遍历stack了。 if (err && err === 'route') { return done(); } var layer = stack[idx++]; //stack遍历结束。 if (!layer) { return done(err); } //没有匹配到layer。 if (layer.method && layer.method !== method) { return next(err); } if (err) { //处理错误。他可以改变err值,例如可以改变成route,让遍历stack结束。 //也可以消除err,继续遍历。也可以是其他错误,继续遍历layer。 layer.handle_error(err, req, res, next); } else { //执行完layer.handler, next(err); layer.handle_request(req, res, next); }
Layer模块
Layer.js作为中间件封装的数据结构,看Layer包的构造函数,
function Layer(path, options, fn) { if (!(this instanceof Layer)) { // this是Layer的实例 return new Layer(path, options, fn); } debug('new %s', path); var opts = options || {}; this.handle = fn; this.name = fn.name || '<anonymous>'; this.params = undefined; this.path = undefined; this.regexp = pathRegexp(path, this.keys = [], opts); if (path === '/' && opts.end === false) { this.regexp.fast_slash = true; } }
该模块包含构造函数和原型上绑定三个功能方法:handle_error、handle_request和match。
handle_error处理请求异常情况;handle_request处理请求正常情况;handler_request可能会抛出错误:
try { fn(req, res, next); //具体的err是由插件来决定的。 } catch (err) { next(err); }
match函数的返回值只有true和false, 当然也可能会抛出错误。
// store values this.params = {}; this.path = m[0]; //第一个元素是输入的路径,后面都是匹配的分组 //this.keys是对path中参数的解释。如path="/user/:foo",:foo是请求中的参数,那么keys=[name:"foo",delimiter:"false"] var keys = this.keys; var params = this.params; for (var i = 1; i < m.length; i++) { var key = keys[i - 1]; var prop = key.name; var val = decode_param(m[i]); //给this.params赋值 if (val !== undefined || !(hasOwnProperty.call(params, prop))) { params[prop] = val; } } return true;
结构如上图:Route、Layer和Router三者的关系。