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. 编写高质量js代码

    原文链接:http://code.tutsplus.com/tutorials/24-javascript-best-practices-for-beginners--net-5399 jquery代 ...

  2. white-space norma nowrap强制同一行内显示所有文本文字,让所有文字内容中一排显示不换行

    日常我们为了让文字内容在一行内显示完,哪怕宽度不够也不能换行,我们可以使用white-space样式,但如果遇到了html br强制换行标签,无论是设置white-space与否都会被<br&g ...

  3. Android SDK的下载和安装

    Android SDK包含的各种库文件.文档.源代码.示例代码……都是通过SDK Tools来下载和安装的,所以我们需要首先下载和安装SDK工具包(SDK Tools Package). 这一步我们可 ...

  4. 在Visual Studio中使用AStyle

    最近在做一个C++项目,我们使用了一个叫做AStyle的插件来做代码格式化. 下载方式1:通过Visual Studio下载 启动Visual Studio,以下简称VS: 英文版VS:VS主菜单 & ...

  5. File System Minifilter Drivers(文件系统微型过滤驱动)入门

    问题: 公司之前有一套文件过滤驱动,但是在实施过程中经常出现问题,现在交由我维护.于是在边看代码的过程中,一边查看官方资料,进行整理. 这套文件过滤驱动的目的只要是根据应用层下发的策略来控制对某些特定 ...

  6. [Design Pattern] Iterator Pattern 简单案例

    Iterator Pattern,即迭代时模式,按照顺序依次遍历集合内的每一个元素,而不用了解集合的底层实现,属于行为类的设计模式.为了方便理解记忆,我也会称其为遍历模式. 下面是一个迭代器模式的简单 ...

  7. 金洪林:红邦创衣止于至善_品牌-生活时尚_品牌_YOKA时尚网

    金洪林:红邦创衣止于至善_品牌-生活时尚_品牌_YOKA时尚网 金洪林:红邦创衣止于至善

  8. 通过百度获取IP地址对应的经纬度

    /** * 获取指定IP对应的经纬度(为空返回当前机器经纬度) *  * @param ip * @return */ public static String[] getIPXY(String ip ...

  9. php中的后期静态绑定("Late Static Binding")

    在我们以往中,在类中使用self关键字的时候都是指向了被调用方法定义时的类,而非原始的调用类. 例如: class Animal{ static $IQ_lv_avg = 1; public stat ...

  10. 各个函数消耗的时间profiling和内存泄漏valgrind

    来源:http://06110120wxc.blog.163.com/blog/static/37788161201333112445844/ ARM(hisi)上面的profiling和valgri ...