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的 ...
随机推荐
- 多线程同步、异步(BeginInvoke)
一.线程的基础知识 1 System.Threading.Thread类 System.Threading.Thread是用于控制线程的基础类,通过Thread可以控制当前应用程序域中线程的创建.挂起 ...
- thead、tbody、tfoot与顺序无关
今天发现一个问题,thead.tbody.tfoot等标签的内容排版与顺序无关,做了一个小的实验:
- 树莓派学习笔记——交叉编译练习之SQLite3安装
0.前言 本博文可能并没有太多使用价值.不过为了练习而练习.在树莓派上使用SQLite有非常多的方法,安装的方法也有非常多. [1]假设使用Python,那么不必安装SQLite由于P ...
- [RxJS] Creation operator: create()
We have been using Observable.create() a lot in previous lessons, so let's take a closer look how do ...
- [AngularJS] Services, Factories, and Providers -- value & Providers
Creating a Value Object Sometimes you have javascript object defined: //value object var droidValue ...
- python使用正則表達式
python中使用正則表達式 1. 匹配字符 正則表達式中的元字符有 . ^ $ * + ? { } [ ] \ | ( ) 匹配字符用的模式有 \d 匹配随意数字 \D 匹配随意非 ...
- C#获取窗口,模拟按键操作
C#获取窗口,模拟按键操作,实现计算器模拟操作.首先引用. using System.Runtime.InteropServices; 使用DllImport引入两个函数: // Get a hand ...
- asp.net微信开发第六篇----高级群发(文本)
说到高级群发,微信的参考资料http://mp.weixin.qq.com/wiki/14/0c53fac3bdec3906aaa36987b91d64ea.html 首先我们先来讲解一下群发文本信息 ...
- 嵌套repeater
通过外层repeater的值来进行内层repeater的数据绑定 前台代码部分: <asp:repeater runat="server" id="repeater ...
- (转,感谢原作者!)既然选择了Linux,有何必在乎这些——Linux wine国服LOL英雄联盟,完美运行!!
Linux下玩国服LOL,国服哦.网络上随处都可以搜到wine美服LOL的教程,但腾讯运营的国服客户端跟美服原版相差比较大,按照美服的方式不能搞起国服LOL,由于宿舍文化,这几天我专注于wine一个国 ...