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. app开发历程——android手机显示服务器端图片思路

    以前自己都不知道怎么去显示服务器端的图片,还好在apkbus论坛上找到一个特别简单的例子.虽然一天天忙忙碌碌,但是自己内心其实有一种想逃的心里,说不定哪天就会冒出来. 1.首先服务器端图片 这里的Im ...

  2. Java---练习:文件切割与合并(1)

    实现对大文件的切割与合并. 按指定个数切(如把一个文件切成10份)或按指定大小切(如每份最大不超过10M),这两种方式都可以. 示例程序说明: 文件切割:把一个文件切割成多个碎片,每个碎片的大小不超过 ...

  3. openStack Use Orchestration module(heat) create and manage cloud resources

  4. Linux操作系统以及各大发行版介绍——Linux operating system and major distribution is introduced

    什么是Linux? 也许很多人会不屑的说,Linux不就是个操作系统么.错!Linux不是一个操作系统,严格来讲,Linux只是一个操作系统中的内核.内核是什么?内核建立了计算机软件与硬件之间通讯的平 ...

  5. Check the quota usage

    stack@ubuntu1:~/Downloads$ nova absolute-limits +--------------------+------+-------+ | Name | Used ...

  6. ssh端口映射,本地转发

    应用场景: # HOSTA<-X->HOSTB 表示A,B两机器相互不可以访问,  HOSTA<-->HOSTB 表示A,B两机器可以相互访问# 1.localhost< ...

  7. object- c 字符串操作

    Objective-C 中核心处理字符串的类是 NSString 与 NSMutableString ,这两个类最大的区别就是NSString 创建赋值以后该字符串的内容与长度不能在动态的更改,除非重 ...

  8. Android的图片压缩类ThumbnailUtils

    从Android 2.2开始系统新增了一个缩略图ThumbnailUtils类,位于framework包下的android.media.ThumbnailUtils位置,可以帮助我们从mediapro ...

  9. CentOS 7 修改hostname

    centOS 7 里面修改hostname的方式有所改变,修改/etc/hosts和/etc/sysconfig/network两个文件已经不能生效.使用的新命令是 : hostnamectl set ...

  10. nginx 3.nginx+fastcgi

    死磕nginx 3.nginx+fastcgi 互联网服务器有个非常典型的架构lamp(linux+apache+mysql+php),由于其开源和强大的兼容性而风靡一时,不过随着nginx的横空出世 ...