这2天看了一点node+express的路由源码有了一点眉目,总结一下

对于app.get,

首先给出一张类图:

图1

注意每个路由有一个stack,这个stack中存放了Layer。

路由系统内有三个文件:

图2

其中layer.js,route.js即为图1中的类的模块。

application.js都只对外层router进行操作

外层路由针对中间件来说的,内层路由针对中间件的链路来说

在index.js中,我认为又对Route做了封装,下面是即为重要的工厂方法

proto.route = function route(path) {
//外层路由构建
var route = new Route(path);//创建内层Route var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: this.strict,
end: true
}, route.dispatch.bind(route)); layer.route = route;//每个外层layer引用一个内层路由 形成循环引用 this.stack.push(layer);
//将构建得到的layer加入外层stack
return route;
};

//外层route的所有HTTP谓词方法的实现
//
methods.concat('all').forEach(function(method){
proto[method] = function(path){
var route = this.route(path)//外层加一层
route[method].apply(route, slice.call(arguments, 1));//调用里层Router谓词 里层加一层
return this;
};
});
app.lazyrouter = function lazyrouter() {
if (!this._router) {
this._router = new Router({
caseSensitive: this.enabled('case sensitive routing'),
strict: this.enabled('strict routing')
}); this._router.use(query(this.get('query parser fn')));
this._router.use(middleware.init(this));
}
};


app.use中间件的实现,可见都用到了路由系统的use方法
app.use = function use(fn) {
var offset = 0;
var path = '/'; // default path to '/'
// disambiguate app.use([fn])
if (typeof fn !== 'function') {
var arg = fn; while (Array.isArray(arg) && arg.length !== 0) {
arg = arg[0];
} // first arg is the path
if (typeof arg !== 'function') {
offset = 1;
path = fn;
}
} var fns = flatten(slice.call(arguments, offset)); if (fns.length === 0) {
throw new TypeError('app.use() requires middleware functions');
} // setup router
this.lazyrouter();
var router = this._router; fns.forEach(function (fn) {
// non-express app
if (!fn || !fn.handle || !fn.set) {
return router.use(path, fn);//外层路由
} debug('.use app under %s', path);
fn.mountpath = path;
fn.parent = this; // restore .app property on req and res
router.use(path, function mounted_app(req, res, next) {//外层路由
var orig = req.app;
fn.handle(req, res, function (err) {
req.__proto__ = orig.request;
res.__proto__ = orig.response;
next(err);
});
});
// mounted an app
fn.emit('mount', this);
}, this); return this;
};

可见调用的是外层路由的use方法,再来看看路由的use方法:(index.js)

proto.use = function use(fn) {
var offset = 0;
var path = '/'; // default path to '/'
// disambiguate router.use([fn])
if (typeof fn !== 'function') {
var arg = fn; while (Array.isArray(arg) && arg.length !== 0) {
arg = arg[0];
} // first arg is the path
if (typeof arg !== 'function') {
offset = 1;
path = fn;
}
} var callbacks = flatten(slice.call(arguments, offset)); if (callbacks.length === 0) {
throw new TypeError('Router.use() requires middleware functions');
} for (var i = 0; i < callbacks.length; i++) {
var fn = callbacks[i]; if (typeof fn !== 'function') {
throw new TypeError('Router.use() requires middleware function but got a ' + gettype(fn));
} // add the middleware
debug('use %s %s', path, fn.name || '<anonymous>'); var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: false,
end: false

}, fn);

  //外层路由构建
layer.route = undefined; this.stack.push(layer);
} return this;
};

可见每个layer对应一个函数,一个stack中有多个layer。并将path传入了Layer中,每次调用use都会创建一个外层layer.

再来看看app.get/post等方法

methods.forEach(function(method){
app[method] = function(path){
if (method === 'get' && arguments.length === 1) {
// app.get(setting)
return this.set(path);
} this.lazyrouter(); var route = this._router.route(path);//外层增加,增加一个外层Layer
route[method].apply(route, slice.call(arguments, 1));
return this;
};
});

methods为所有HTTP谓词等的数组,所有的app.METHOD都适用里层Router的谓词

,调用内层Router,对于内层Router的HTTP谓词:

methods.forEach(function(method){
Route.prototype[method] = function(){
var handles = flatten(slice.call(arguments)); for (var i = 0; i < handles.length; i++) {
var handle = handles[i]; if (typeof handle !== 'function') {
var type = toString.call(handle);
var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
throw new Error(msg);
} debug('%s %s', method, this.path); var layer = Layer('/', {}, handle);//内层Layer
layer.method = method; this.methods[method] = true;
this
.stack.push(layer);//内层Layer
} return this;
};
});

所有的get/post等都是在内层Router的stack上增加Layer

可见不管是use,还是get/post 最后都是在增加Layer,对于use,增加外层layer,对于get/post,既增加外层layer,又增加内层layer

Node.js express路由简单分析的更多相关文章

  1. Node.js Express 路由文件分类

    前言 基于上一篇Web Api Controller分类,在MVC中我们通常要按自己的业务来划分Controller层, 好处多多,那么Express框架作为Node.js的一款MVC框架,那么自然也 ...

  2. Node.js Express 框架学习

    转载:http://JavaScript.ruanyifeng.com/nodejs/express.html#toc0 感觉很牛的样子,不过觉得对初学者没太大用,里面很多例子用的api都没有详细的说 ...

  3. Nodejs学习笔记(六)--- Node.js + Express 构建网站预备知识

    目录 前言 新建express项目并自定义路由规则 如何提取页面中的公共部分? 如何提交表单并接收参数? GET 方式 POST 方式 如何字符串加密? 如何使用session? 如何使用cookie ...

  4. Nodejs学习笔记(六)—Node.js + Express 构建网站预备知识

    前言 前面经过五篇Node.js的学习,基本可以开始动手构建一个网站应用了,先用这一篇了解一些构建网站的知识! 主要是些基础的东西... 如何去创建路由规则.如何去提交表单并接收表单项的值.如何去给密 ...

  5. node.js + express 初体验【hello world】

    [node.js]  一个神奇的XX 呵呵 :) 不知道怎么形容他才好! [express] 是node.js 开发web应用程序的框架 开发环境:XP 大家共同进步吧 :) 一:前期准备: 1:下载 ...

  6. modeJS 深了解(1): Node.js + Express 构建网站预备知识

    转载:http://www.cnblogs.com/zhongweiv/p/nodejs_express_webapp1.html 目录 前言 新建express项目并自定义路由规则 如何提取页面中的 ...

  7. Node.js Express框架

    Express 介绍 Express是一个最小的,灵活的Node.js Web应用程序框架,它提供了一套强大的功能来开发Web和移动应用程序. 它有助于基于Node Web应用程序的快速开发.下面是一 ...

  8. node.js express mvc轻量级框架实践

    本文记录的是笔者最近抽私下时间给朋友做的一个时时彩自动下注系统,比较简单,主要也是为了学习一下node.js. 其实逻辑没什么可以深谈的,主要是想说说这套代码结构.结构如下图: js的代码比较难以维护 ...

  9. body-parser Node.js(Express) HTTP请求体解析中间件

    body-parser Node.js(Express) HTTP请求体解析中间件 2016年06月08日     781     声明 在HTTP请求中,POST.PUT和PATCH三种请求方法中包 ...

随机推荐

  1. 解决 window server2008 r2 没有注册Ofiice组件的方法

    解决 window server2008  r2 没有注册Ofiice组件的方法   .NET下在用Microsoft.Office.Interop.Excel及word 操作Excel和Word时, ...

  2. JAVA中求解对象所占字节大小

    该类为cache4j缓存框架中的工具类方法,该方法实现了两个接口 接口1:计算对象在内存中所占字节数 接口2:复制对象,实现深度克隆效果,实现原理为先序列化对象,然后在反序列化对象:返回一个新的对象, ...

  3. &&和||的那点事儿

    以前一直以为&&和||的运算结果就是布尔值,但今天看到一段代码又填补的一些知识漏洞. var a = (1&&2&&5) || 3; console.l ...

  4. maven的安装与配置

    1.下载相应版本的maven安装包(压缩文件) http://maven.apache.org/download.cgi 2.环境变量配置 将下载的压缩包解压. 计算机===>属性=====&g ...

  5. 为什么你不应该自行更新 Drupal 网站?

    (译注:这篇文章主要还是针对于非专业人员及个人Drupal站长,对于专业的 Drupal 团队和公司而言 Drupal 的升级更新都有规范的操作流程,完全是家常便饭,不可能出现文中出现的这些情况.尽管 ...

  6. Git 图解剖析

    git中文件内容并没有真正存储在索引(.git/index)或者提交对象中,而是以blob的形式分别存储在数据库中(.git/objects),并用SHA-1值来校验. 索引文件用识别码列出相关的bl ...

  7. Ajax-(get/post/jQuery方式请求)

    < !DOCTYPE html > < html xmlns = "http://www.w3.org/1999/xhtml" > < head &g ...

  8. Visual studio 2013 Team Foundation Server TFS2013 设置签出独占锁

    摘自: http://www.cnblogs.com/52XF/p/4239056.html 以备自查 如侵权,请告知

  9. 0329 复利计算器5.0 Juint单元测试 组员 254列志华 253韩麒麟

    一.主要功能与需求分析 1.本金为100万,利率或者投资回报率为3%,投资年限为30年,那么,30年后所获得的利息收入:按复利计算公式来计算就是:1,000,000×(1+3%)^30 2.如果按照单 ...

  10. Android窗口为弹出框样式

    1.XML android:theme="@android:style/Theme.Dialog <?xml version="1.0" encoding=&quo ...