Node.js express路由简单分析

这2天看了一点node+express的路由源码有了一点眉目,总结一下

对于app.get,

 

 

首先给出一张类图:

 

图1

注意每个路由有一个stack,这个stack中存放了Layer。

路由系统内有三个文件:

图2

其中layer.js,route.js即为图1中的类的模块。

application.js都只对外层router进行操作

外层路由针对中间件来说的,内层路由针对中间件的链路来说

在index.js中,我认为又对Route做了封装,下面是即为重要的工厂方法

proto.route = function route(path) {
//外层路由构建
var route = new Route(path);//创建内层Route var layer = new Layer(path, { sensitive: this.caseSensitive, strict: this.strict, end: true }, route.dispatch.bind(route)); layer.route = route;//每个外层layer引用一个内层路由 形成循环引用 this.stack.push(layer);
//将构建得到的layer加入外层stack
return route; };

//外层route的所有HTTP谓词方法的实现
//
methods.concat('all').forEach(function(method){ proto[method] = function(path){ var route = this.route(path)//外层加一层 route[method].apply(route, slice.call(arguments, 1));//调用里层Router谓词 里层加一层 return this; }; });
app.lazyrouter = function lazyrouter() {
  if (!this._router) {
    this._router = new Router({
      caseSensitive: this.enabled('case sensitive routing'),
      strict: this.enabled('strict routing')
    });

    this._router.use(query(this.get('query parser fn')));
    this._router.use(middleware.init(this));
  }
};


app.use中间件的实现,可见都用到了路由系统的use方法
app.use = function use(fn) {
  var offset = 0;
  var path = '/';

  // default path to '/'
  // disambiguate app.use([fn])
  if (typeof fn !== 'function') {
    var arg = fn;

    while (Array.isArray(arg) && arg.length !== 0) {
      arg = arg[0];
    }

    // first arg is the path
    if (typeof arg !== 'function') {
      offset = 1;
      path = fn;
    }
  }

  var fns = flatten(slice.call(arguments, offset));

  if (fns.length === 0) {
    throw new TypeError('app.use() requires middleware functions');
  }

  // setup router
  this.lazyrouter();
  var router = this._router;

  fns.forEach(function (fn) {
    // non-express app
    if (!fn || !fn.handle || !fn.set) {
      return router.use(path, fn);//外层路由
    }

    debug('.use app under %s', path);
    fn.mountpath = path;
    fn.parent = this;

    // restore .app property on req and res
    router.use(path, function mounted_app(req, res, next) {//外层路由
      var orig = req.app;
      fn.handle(req, res, function (err) {
        req.__proto__ = orig.request;
        res.__proto__ = orig.response;
        next(err);
      });
    });

    // mounted an app
    fn.emit('mount', this);
  }, this);

  return this;
};

可见调用的是外层路由的use方法,再来看看路由的use方法:(index.js)

proto.use = function use(fn) {
  var offset = 0;
  var path = '/';

  // default path to '/'
  // disambiguate router.use([fn])
  if (typeof fn !== 'function') {
    var arg = fn;

    while (Array.isArray(arg) && arg.length !== 0) {
      arg = arg[0];
    }

    // first arg is the path
    if (typeof arg !== 'function') {
      offset = 1;
      path = fn;
    }
  }

  var callbacks = flatten(slice.call(arguments, offset));

  if (callbacks.length === 0) {
    throw new TypeError('Router.use() requires middleware functions');
  }

  for (var i = 0; i < callbacks.length; i++) {
    var fn = callbacks[i];

    if (typeof fn !== 'function') {
      throw new TypeError('Router.use() requires middleware function but got a ' + gettype(fn));
    }

    // add the middleware
    debug('use %s %s', path, fn.name || '<anonymous>');

    var layer = new Layer(path, {
      sensitive: this.caseSensitive,
      strict: false,
      end: false
    }, fn);
  //外层路由构建
    layer.route = undefined;

    this.stack.push(layer);
  }

  return this;
};

可见每个layer对应一个函数,一个stack中有多个layer。并将path传入了Layer中,每次调用use都会创建一个外层layer.

再来看看app.get/post等方法

methods.forEach(function(method){
  app[method] = function(path){
    if (method === 'get' && arguments.length === 1) {
      // app.get(setting)
      return this.set(path);
    }

    this.lazyrouter();

    var route = this._router.route(path);//外层增加,增加一个外层Layer
    route[method].apply(route, slice.call(arguments, 1));
    return this;
  };
});

methods为所有HTTP谓词等的数组,所有的app.METHOD都适用里层Router的谓词

,调用内层Router,对于内层Router的HTTP谓词:

methods.forEach(function(method){
  Route.prototype[method] = function(){
    var handles = flatten(slice.call(arguments));

    for (var i = 0; i < handles.length; i++) {
      var handle = handles[i];

      if (typeof handle !== 'function') {
        var type = toString.call(handle);
        var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
        throw new Error(msg);
      }

      debug('%s %s', method, this.path);

      var layer = Layer('/', {}, handle);//内层Layer
      layer.method = method;

      this.methods[method] = true;
      this.stack.push(layer);//内层Layer
    }

    return this;
  };
});

所有的get/post等都是在内层Router的stack上增加Layer

 

可见不管是use,还是get/post 最后都是在增加Layer,对于use,增加外层layer,对于get/post,既增加外层layer,又增加内层layer

posted @ 2016-04-15 23:01  电阻起火lyt  阅读(1669)  评论(0编辑  收藏  举报