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

express源码剖析--Router模块的更多相关文章

  1. .5-浅析express源码之Router模块(1)-默认中间件

    模块application已经完结,开始讲Router路由部分. 切入口仍然在application模块中,方法就是那个随处可见的lazyrouter. 基本上除了初始化init方法,其余的app.u ...

  2. .7-浅析express源码之Router模块(3)-app[METHODS]

    之前的讨论都局限于use方法,所有方式的请求会被通过,这一节讨论express内部如何处理特殊请求方法. 给个流程图咯~ 分别给出app.METHODS与router.METHODS: // app. ...

  3. .6-浅析express源码之Router模块(2)-router.use

    这一节继续深入Router模块,首先从最常用的use开始. router.use 方法源码如下: proto.use = function use(fn) { var offset = 0; var ...

  4. express源码剖析2

    当使用express时,代码会这样写: var express = require('express'); 如果创建一个express的应用,代码会这样写: var app = express(); ...

  5. .2-浅析express源码之applicaiton模块(1)-咸鱼方法

    上一节讲了express的入口文件,当执行主函数,会调用app.init方法,这个方法就来源于application模块. 这个模块有很多方法,目前仅仅过一下初始化方法: app.init = fun ...

  6. .3-浅析express源码之applicaiton模块(2)-app.render

    这个模块还漏了一个稍微复杂点的API,就是app.render,首先看官网的定义: app.render(view, [locals], callback) view为对应的文件名,locals为一个 ...

  7. .4-浅析express源码之applicaiton模块(3)-compile函数

    基本上application模块的api都看的差不多了,但是在app.set中还有一个遗漏点,如下: app.set = function set(setting, val) { // ...设值 / ...

  8. express源码剖析1

    在通读源码之前,先把一些比较难理解的代码吃透: 1.EventEmitter.prototype mixin(app, EventEmitter.prototype, false); app为一个函数 ...

  9. express源码分析之Router

    express作为nodejs平台下非常流行的web框架,相信大家都对其已经很熟悉了,对于express的使用这里不再多说,如有需要可以移步到www.expressjs.com自行查看express的 ...

随机推荐

  1. URL图片预览(createObjectURL)

    1.说明 1)createObjectURL 作用:创建url(creates  a URL for the specified object); 语法:var url = URL.createObj ...

  2. Clipboard.js : 移动端浏览器实现网页内容复制

    .bl { padding: 5px 10px; border-left: 3px solid #009a61; background: #f6f6f6; color: #555; font-size ...

  3. c++对象模型之Data布局

    Data语意学 class X{}; class Y : publicvirtual X {}; class Z : publicvirtual X {}; class A : publicY, pu ...

  4. win7 vs2010 安装cocos2d-x

    http://blog.csdn.net/leoncoder/article/details/12523727 新安装搭建cocos2d-X的跳过这里,看以下红色開始: cocos2d-x删除vs20 ...

  5. POJ 2044 Weather Forecast

    意甲冠军:有一2*2云,而一个4*4范围.在当天密布区必须有雨.有云4招式种类 .期间希望不要下雨,并且一个地方不能有连续7天没下雨. 思路:首先解决一个地方不能有连续7天没下雨的情况,要让地图上的全 ...

  6. Android 自定义View (四) 视频音量调控

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24529807 今天没事逛eoe,看见有人求助要做一个下面的效果,我看下面一哥们说 ...

  7. php开启ssl支持

    1.首先在php的安装文件下找到三个文件 并copy到系统目标下的 system32文件夹下: ssleay32.dll.libeay32.dll,php_openssl.dll. 2.打开php.i ...

  8. [转] GPS坐标转换经纬度及换算方法

    GPS坐标和经纬度的算法和概率不太一样,但是我们可能会将他们互通起来用,下面先贴上我做的转换工具:http://map.yanue.net/gps.html.里面实现了gps到谷歌地图百度地图经纬度的 ...

  9. codevs 2995 楼房

    /*暴力30分*/ #include<iostream> #include<cstring> #include<cstdio> #include<map> ...

  10. C#中的序列化与反序列化

    眼看XX鸟的课程关于C#的知识点就要学完了,翻看网络中流传的教程还是发现了一个课程中没有讲到的知识点:序列化与反序列化 无奈还是了解一下并操作一番,以备后用吧 介绍:就是将对象信息转化为二进制信息以便 ...