Node.js express路由简单分析
这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 = 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路由简单分析的更多相关文章
- Node.js Express 路由文件分类
前言 基于上一篇Web Api Controller分类,在MVC中我们通常要按自己的业务来划分Controller层, 好处多多,那么Express框架作为Node.js的一款MVC框架,那么自然也 ...
- Node.js Express 框架学习
转载:http://JavaScript.ruanyifeng.com/nodejs/express.html#toc0 感觉很牛的样子,不过觉得对初学者没太大用,里面很多例子用的api都没有详细的说 ...
- Nodejs学习笔记(六)--- Node.js + Express 构建网站预备知识
目录 前言 新建express项目并自定义路由规则 如何提取页面中的公共部分? 如何提交表单并接收参数? GET 方式 POST 方式 如何字符串加密? 如何使用session? 如何使用cookie ...
- Nodejs学习笔记(六)—Node.js + Express 构建网站预备知识
前言 前面经过五篇Node.js的学习,基本可以开始动手构建一个网站应用了,先用这一篇了解一些构建网站的知识! 主要是些基础的东西... 如何去创建路由规则.如何去提交表单并接收表单项的值.如何去给密 ...
- node.js + express 初体验【hello world】
[node.js] 一个神奇的XX 呵呵 :) 不知道怎么形容他才好! [express] 是node.js 开发web应用程序的框架 开发环境:XP 大家共同进步吧 :) 一:前期准备: 1:下载 ...
- modeJS 深了解(1): Node.js + Express 构建网站预备知识
转载:http://www.cnblogs.com/zhongweiv/p/nodejs_express_webapp1.html 目录 前言 新建express项目并自定义路由规则 如何提取页面中的 ...
- Node.js Express框架
Express 介绍 Express是一个最小的,灵活的Node.js Web应用程序框架,它提供了一套强大的功能来开发Web和移动应用程序. 它有助于基于Node Web应用程序的快速开发.下面是一 ...
- node.js express mvc轻量级框架实践
本文记录的是笔者最近抽私下时间给朋友做的一个时时彩自动下注系统,比较简单,主要也是为了学习一下node.js. 其实逻辑没什么可以深谈的,主要是想说说这套代码结构.结构如下图: js的代码比较难以维护 ...
- body-parser Node.js(Express) HTTP请求体解析中间件
body-parser Node.js(Express) HTTP请求体解析中间件 2016年06月08日 781 声明 在HTTP请求中,POST.PUT和PATCH三种请求方法中包 ...
随机推荐
- MFC学习 画图设置字体按钮风格
修改按钮样式时, 设置按钮关联哪个按钮类, 按钮类是自己写的, 从CButton继承, 重写DrawItem可修改按钮样式. 代码中包括画线, 点, 圆, 设置这些的样式, 如线粗, 颜色, 字体. ...
- QTP 场景恢复– 函数调用
创建自动化测试是为了实现无人值守下运行,但也给开发人员带来一些问题.假如你离开办公室前启动测试,想要让它通宵运行.然而,由于不可预见的错误,您的测试会在某一点停止,中断了测试结果.因此QTP中引入场景 ...
- 国内外CDN服务商CNAME特征串调研
总结 此篇博文给特定需求的人群使用,通过CNAME的某些特征串,确定其使用的是哪家CDN,大多是国外的CDN,国内的CDN厂商只有几个,格式为:[来源地址]+[截图]+[猜测的特征串],整体博文较长, ...
- iosiOS 地图 自定义以及添加锚点
- (void)clickLongPress:(UILongPressGestureRecognizer *)longPress { CGPoint point = [longPress locati ...
- gson转换带有objectId的问题
/** * * @Description: objectid 转换成string 不然就会objectid对象序列化了 * @param @param obj * @param @return * @ ...
- js中object的申明方法
//js中的对象申明使用new Object(); //object类型的数据类似于数组通过下表来访问其中的值 //example1 var person=new Object(); person.n ...
- hbase blocksize设置,与hdfs关系
关于如何设定数据块的大小,我们应用一段HFile源码中的注释: 我们推荐将数据块的大小设置为8KB至1MB.大的数据块比较适合顺序的查询(比如Scan),但不适合随机查询,想想看,每一次随机查询可能都 ...
- sql server 分组后字段拼接
- 彻底解决_OBJC_CLASS_$_某文件名", referenced from:问题转
最近在使用静态库时,总是出现这个问题.下面总结一下我得解决方法: 1. .m文件没有导入 在Build Phases里的Compile Sources 中添加报错的文件 2. .framework ...
- Eclipse 中打不开android sdk managerf
今天配置android sdk 的时候,出现了android sdk 打不开的情况.无论直接点击 sdk manager.exe 还是从eclipse启动,都不起作用,双重启(重启eclipse和ad ...