express源码剖析--Router模块和Layer模块

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三者的关系。

 

posted @ 2017-01-09 18:11  anthonyliu  阅读(893)  评论(0编辑  收藏  举报