express源码剖析--Router模块
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模块的更多相关文章
- .5-浅析express源码之Router模块(1)-默认中间件
模块application已经完结,开始讲Router路由部分. 切入口仍然在application模块中,方法就是那个随处可见的lazyrouter. 基本上除了初始化init方法,其余的app.u ...
- .7-浅析express源码之Router模块(3)-app[METHODS]
之前的讨论都局限于use方法,所有方式的请求会被通过,这一节讨论express内部如何处理特殊请求方法. 给个流程图咯~ 分别给出app.METHODS与router.METHODS: // app. ...
- .6-浅析express源码之Router模块(2)-router.use
这一节继续深入Router模块,首先从最常用的use开始. router.use 方法源码如下: proto.use = function use(fn) { var offset = 0; var ...
- express源码剖析2
当使用express时,代码会这样写: var express = require('express'); 如果创建一个express的应用,代码会这样写: var app = express(); ...
- .2-浅析express源码之applicaiton模块(1)-咸鱼方法
上一节讲了express的入口文件,当执行主函数,会调用app.init方法,这个方法就来源于application模块. 这个模块有很多方法,目前仅仅过一下初始化方法: app.init = fun ...
- .3-浅析express源码之applicaiton模块(2)-app.render
这个模块还漏了一个稍微复杂点的API,就是app.render,首先看官网的定义: app.render(view, [locals], callback) view为对应的文件名,locals为一个 ...
- .4-浅析express源码之applicaiton模块(3)-compile函数
基本上application模块的api都看的差不多了,但是在app.set中还有一个遗漏点,如下: app.set = function set(setting, val) { // ...设值 / ...
- express源码剖析1
在通读源码之前,先把一些比较难理解的代码吃透: 1.EventEmitter.prototype mixin(app, EventEmitter.prototype, false); app为一个函数 ...
- express源码分析之Router
express作为nodejs平台下非常流行的web框架,相信大家都对其已经很熟悉了,对于express的使用这里不再多说,如有需要可以移步到www.expressjs.com自行查看express的 ...
随机推荐
- HDOJ 1287 破译密码(异或运算)
Problem Description 有个叫"猪头帮"的国家,采用一种简单的文法加密,他们所用的语言里面只有大写字母,没有其他任何字符:现在还知道他们加密的方法是:只用一个大写字 ...
- 夏普比率(Sharpe Ratio)
投资中有一个常规的特点,即投资标的的预期报酬越高,投资人所能忍受的波动风险越高:反之,预期报酬越低,波动风险也越低.所以理性的投资人选择投资标的与投资组合的主要目的为:在固定所能承受的风险下,追求最大 ...
- Linux动态库的编译与使用
转载: http://hi.baidu.com/linuxlife/blog/item/0d3e302ae2384d3a5343c1b1.html Linux下的动态库以.so为后缀,我也是初次在Li ...
- acm - cry for no one
再一次回到实验室,距离上次已经四个多月了.诸多业障,三界无安,犹如火灾,众若充满,甚可怖畏,常有生老病死 忧患,如是等火,炽然不息.<成实论>云:“万法刹那生,万法刹那灭,转转相续也”.又 ...
- Android学习之电话拨号器
本人自己是做android驱动的,也会接触到系统层.上层的应用,所以在闲暇的时候也就开始了学习android应用的路程,在这里把这些东西记下来,希望自己能坚持下去,也好以后复习用. 今天先实现一个简单 ...
- jquery width(), innerWidth(), outerWidth() 区别
#div1 { width: 100px; height: 100px; border: 5px black solid; padding: 10px; margin: 10px; backgroun ...
- IE 文档模型设置 免去你IE 按F12去调文档标准的烦恼。
英文原文:http://msdn.microsoft.com/en-us/library/cc288325(VS.85).aspx 最近在做一个前端页面,在各种浏览器上,各种差异,各种无赖.各种郁闷. ...
- Android-Uiautomator:[5]停止monkey测试
方法/步骤 1 其实停止很简单,无非就是结束掉monkey的进程即可 如何停止呢 2 ps命令 查找uiautomator的进程 打开cmd命令行窗口 输入: adb shell ps | grep ...
- IntelliJ IDEA 中module的dependencies是其它module时的注意事项
Dependencies on other modules If a module (module A) depends on another module (module B), IntelliJ ...
- Java基础知识强化81:Math类random()方法之获取任意范围的随机数案例(面试题)
1. 需求:设计一个方法,可以实现获取任意范围内的随机数 分析:使用方法random()如下: public static double random() 注:Returns a pseudo-ran ...