博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
nodejs express 框架解密4-路由
阅读量:6158 次
发布时间:2019-06-21

本文共 6618 字,大约阅读时间需要 22 分钟。

本文档是基于express3.4.6

express 的路由是自己去实现的,没有使用connect中的路由中间件模块。

1、在如何创建一个app那篇中,我们提到了路由,

//router  //路由  this._router = new Router(this);  this.routes = this._router.map;  this.__defineGetter__('router', function(){    this._usedRouter = true;    this._router.caseSensitive = this.enabled('case sensitive routing');    this._router.strict = this.enabled('strict routing');    return this._router.middleware;  });

可以看到,是将Router这个类存储到了app上的_rounter这个属性上去了,然后将所有得路由映射存储到了routes 这个属性上了。最后在给app定义一个router属性,直接调用了这个模块的

middleware模块。我们来看看Router类

function Router(options) {  options = options || {};  var self = this;  this.map = {};  this.params = {};  this._params = [];  this.caseSensitive = options.caseSensitive;  this.strict = options.strict;  this.middleware = function router(req, res, next){    self._dispatch(req, res, next);  };}

从上面的代码可以看出,middleware调用了自身的_dispatch 函数 ,这个函数的作用就是路由分发

Router.prototype._dispatch = function(req, res, next){  var params = this.params    , self = this;  debug('dispatching %s %s (%s)', req.method, req.url, req.originalUrl);  // route dispatch  (function pass(i, err){    var paramCallbacks      , paramIndex = 0      , paramVal      , route      , keys      , key;    // match next route    function nextRoute(err) {      pass(req._route_index + 1, err);    }    // match route    req.route = route = self.matchRequest(req, i);    // implied OPTIONS    if (!route && 'OPTIONS' == req.method) return self._options(req, res);    // no route    if (!route) return next(err);    debug('matched %s %s', route.method, route.path);    // we have a route    // start at param 0    req.params = route.params;    keys = route.keys;    i = 0;    // param callbacks    function param(err) {      paramIndex = 0;      key = keys[i++];      paramVal = key && req.params[key.name];      paramCallbacks = key && params[key.name];      try {        if ('route' == err) {          nextRoute();        } else if (err) {          i = 0;          callbacks(err);        } else if (paramCallbacks && undefined !== paramVal) {          paramCallback();        } else if (key) {          param();        } else {          i = 0;          callbacks();        }      } catch (err) {        param(err);      }    };    param(err);    // single param callbacks    function paramCallback(err) {      var fn = paramCallbacks[paramIndex++];      if (err || !fn) return param(err);      fn(req, res, paramCallback, paramVal, key.name);    }    // invoke route callbacks    function callbacks(err) {      var fn = route.callbacks[i++];      try {        if ('route' == err) {          nextRoute();        } else if (err && fn) {          if (fn.length < 4) return callbacks(err);          fn(err, req, res, callbacks);        } else if (fn) {          if (fn.length < 4) return fn(req, res, callbacks);          callbacks();        } else {          nextRoute(err);        }      } catch (err) {        callbacks(err);      }    }  })(0);};

这个函数是通过pass 这个自动执行的函数进行路由转发的,

首先通过请求, req.route = route = self.matchRequest(req, i); 来配置路由,返回需要的信息

可以看到matchRequest 函数返回了(我访问了下http://localhost:3000)

{ path: '/',  method: 'get',  callbacks: [ [Function] ],  keys: [],  regexp: /^\/\/?$/i,  params: [] }

看看 matchRequest 这个函数

Router.prototype.matchRequest = function(req, i, head){  var method = req.method.toLowerCase()    , url = parse(req)    , path = url.pathname    , routes = this.map    , i = i || 0    , route;  // HEAD support  if (!head && 'head' == method) {    route = this.matchRequest(req, i, true);    if (route) return route;     method = 'get';  }  // routes for this method  if (routes = routes[method]) {    // matching routes    for (var len = routes.length; i < len; ++i) {      route = routes[i];      if (route.match(path)) {        req._route_index = i;        return route;      }    }  }};

它返回一个路由的处理结果。

后面根据参数执行了param() 函数。这个函数主要是处理callback回调函数的。

2.给路由注册各种函数:

methods.forEach(function(method){  app[method] = function(path){    if ('get' == method && 1 == arguments.length) return this.set(path);    // deprecated    if (Array.isArray(path)) {      console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0');    }    // if no router attached yet, attach the router    if (!this._usedRouter) this.use(this.router);    // setup route    console.log(method,'test2');    this._router[method].apply(this._router, arguments);    return this;  };});

这个函数直接添加了开始的注册函数,下面的这个methods.foreach 依次为每一个app.get,app.post 等等 添加路由和 callback 函数

Router.prototype.route = function(method, path, callbacks){  var method = method.toLowerCase()    , callbacks = utils.flatten([].slice.call(arguments, 2));  // ensure path was given  if (!path) throw new Error('Router#' + method + '() requires a path');  // ensure all callbacks are functions  callbacks.forEach(function(fn){    if ('function' == typeof fn) return;    var type = {}.toString.call(fn);    var msg = '.' + method + '() requires callback functions but got a ' + type;    throw new Error(msg);  });  // create the route  debug('defined %s %s', method, path);  var route = new Route(method, path, callbacks, {    sensitive: this.caseSensitive,    strict: this.strict  });  // add it  (this.map[method] = this.map[method] || []).push(route);  return this;};Router.prototype.all = function(path) {  var self = this;  var args = [].slice.call(arguments);  methods.forEach(function(method){      self.route.apply(self, [method].concat(args));  });  return this;};methods.forEach(function(method){  Router.prototype[method] = function(path){    var args = [method].concat([].slice.call(arguments));    this.route.apply(this, args);    return this;  };});

最后一个函数,直接执行,给路由添加get,post等函数。

在Router.prototype.route  函数中,我们调用了一个:

var route = new Route(method, path, callbacks, {    sensitive: this.caseSensitive,    strict: this.strict  });

Route 是一个路由的基本单元,包含2个方法:

function Route(method, path, callbacks, options) {  options = options || {};  this.path = path;  this.method = method;  this.callbacks = callbacks;  this.regexp = utils.pathRegexp(path    , this.keys = []    , options.sensitive    , options.strict);}/** * Check if this route matches `path`, if so * populate `.params`. * * @param {String} path * @return {Boolean} * @api private */Route.prototype.match = function(path){  var keys = this.keys    , params = this.params = []    , m = this.regexp.exec(path);  if (!m) return false;  for (var i = 1, len = m.length; i < len; ++i) {    var key = keys[i - 1];    var val = 'string' == typeof m[i]      ? utils.decode(m[i])      : m[i];    if (key) {      params[key.name] = val;    } else {      params.push(val);    }  }  return true;}; 

转载地址:http://uqafa.baihongyu.com/

你可能感兴趣的文章
设计模式:组合模式(Composite Pattern)
查看>>
ContentValues 和HashTable区别
查看>>
LogicalDOC 6.6.2 发布,文档管理系统
查看>>
给PowerShell脚本传递参数
查看>>
实战2——Hadoop的日志分析
查看>>
利用FIFO进行文件拷贝一例
查看>>
Ecshop安装过程中的的问题:cls_image::gd_version()和不支持JPEG
查看>>
resmgr:cpu quantum等待事件
查看>>
一个屌丝程序猿的人生(六十六)
查看>>
Java 编码 UTF-8
查看>>
SpringMVC实战(注解)
查看>>
关于静态属性和静态函数
查看>>
进程的基本属性:进程ID、父进程ID、进程组ID、会话和控制终端
查看>>
spring+jotm+ibatis+mysql实现JTA分布式事务
查看>>
MyBatis启动:MapperStatement创建
查看>>
调查问卷相关
查看>>
eclipse启动无响应,老是加载不了revert resources,或停留在Loading workbench状态
查看>>
1. Git-2.12.0-64-bit .exe下载
查看>>
怎样关闭“粘滞键”?
查看>>
[转]React 教程
查看>>