这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. Android开发-API指南-<category>

    <category> 英文原文:http://developer.android.com/guide/topics/manifest/category-element.html 采集(更新 ...

  2. 004.ASP.NET MVC中的HTML Helpers

    原文链接:http://www.codeproject.com/Articles/794579/ASP-NET-MVC-HTML-Helpers-A-MUST-KNOW 1.什么是HTML Helpe ...

  3. 图形设备接口(GDI)

    图形设备接口(GDI,Graphics Device Interface)负责在显示器和打印机上显示图形.GDI 是由几百个函数和一些相关的数据类型.宏和结构构成的.Windows 98/NT 中的图 ...

  4. windows 创建服务提示失败 5 拒绝 访问拒绝

    1.桌面创建文本,输入 sc create .....echo. & pause 保存,重命名为   .bat 2.右键该文件,管理员运行

  5. C++临时变量的生命周期

    C++ 中的临时变量指的是那些由编译器根据需要在栈上产生的,没有名字的变量.主要的用途主要有两类: 1) 函数的返回值, 如: string proc() { return string(" ...

  6. Windows API学习---用户方式中的线程同步

    前言 当所有的线程在互相之间不需要进行通信的情况下就能够顺利地运行时, Micrsoft Windows的运行性能最好.但是,线程很少能够在所有的时间都独立地进行操作.通常情况下,要生成一些线程来处理 ...

  7. word-wrap:break-word和word-break:break-all的小小比较

    个人感觉word-break:break-all;的用法比word-wrap:break-word;要好点, 当然这是出于某些需求而言,下面简单说下word-break:break-all的优点 wo ...

  8. 【IHttpHandler】HttpModule,HttpHandler,HttpHandlerFactory简单使用

    这三个对象我们在开发Asp.net程序时经常会用到,似乎很熟悉,但有时候又不太确定.本文通过一个简单的例子来直观的比较一下这三个对象的使用. HttpModule:Http模块,可以在页面处理前后.应 ...

  9. A Neural Probabilistic Language Model

    A Neural Probabilistic Language Model,这篇论文是Begio等人在2003年发表的,可以说是词表示的鼻祖.在这里给出简要的译文 A Neural Probabili ...

  10. kbengine mmo源码(完整服务端源码+资源+完整客户端源码)

      本项目作为kbengine服务端引擎的客户端演示而写 更新kbengine插件库(https://github.com/kbengine/kbengine_unity3d_plugins):    ...