本文档是基于express3.4.6

express 的路由是自己去实现的,没有使用connect中的路由中间件模块。

1、在如何创建一个app那篇中,我们提到了路由,

  //router
//路由
this._router = new Router(this);
this.routes = this._router.map;
this.__defineGetter__('router', function(){
this._usedRouter = true;
this._router.caseSensitive = this.enabled('case sensitive routing');
this._router.strict = this.enabled('strict routing');
return this._router.middleware;
});

可以看到,是将Router这个类存储到了app上的_rounter这个属性上去了,然后将所有得路由映射存储到了routes 这个属性上了。最后在给app定义一个router属性,直接调用了这个模块的

middleware模块。我们来看看Router类

function Router(options) {
options = options || {};
var self = this;
this.map = {};
this.params = {};
this._params = [];
this.caseSensitive = options.caseSensitive;
this.strict = options.strict;
this.middleware = function router(req, res, next){
self._dispatch(req, res, next);
};
}

从上面的代码可以看出,middleware调用了自身的_dispatch 函数 ,这个函数的作用就是路由分发

Router.prototype._dispatch = function(req, res, next){
var params = this.params
, self = this; debug('dispatching %s %s (%s)', req.method, req.url, req.originalUrl); // route dispatch
(function pass(i, err){
var paramCallbacks
, paramIndex = 0
, paramVal
, route
, keys
, key; // match next route
function nextRoute(err) {
pass(req._route_index + 1, err);
} // match route
req.route = route = self.matchRequest(req, i);
// implied OPTIONS
if (!route && 'OPTIONS' == req.method) return self._options(req, res); // no route
if (!route) return next(err);
debug('matched %s %s', route.method, route.path); // we have a route
// start at param 0
req.params = route.params;
keys = route.keys;
i = 0; // param callbacks
function param(err) {
paramIndex = 0;
key = keys[i++];
paramVal = key && req.params[key.name];
paramCallbacks = key && params[key.name]; try {
if ('route' == err) {
nextRoute();
} else if (err) {
i = 0;
callbacks(err);
} else if (paramCallbacks && undefined !== paramVal) {
paramCallback();
} else if (key) {
param();
} else {
i = 0;
callbacks();
}
} catch (err) {
param(err);
}
}; param(err); // single param callbacks
function paramCallback(err) {
var fn = paramCallbacks[paramIndex++];
if (err || !fn) return param(err);
fn(req, res, paramCallback, paramVal, key.name);
} // invoke route callbacks
function callbacks(err) {
var fn = route.callbacks[i++]; try {
if ('route' == err) {
nextRoute();
} else if (err && fn) {
if (fn.length < 4) return callbacks(err);
fn(err, req, res, callbacks);
} else if (fn) {
if (fn.length < 4) return fn(req, res, callbacks);
callbacks();
} else {
nextRoute(err);
}
} catch (err) {
callbacks(err);
}
}
})(0);
};

这个函数是通过pass 这个自动执行的函数进行路由转发的,

首先通过请求, req.route = route = self.matchRequest(req, i); 来配置路由,返回需要的信息

可以看到matchRequest 函数返回了(我访问了下http://localhost:3000)

{ path: '/',
method: 'get',
callbacks: [ [Function] ],
keys: [],
regexp: /^\/\/?$/i,
params: []
}

看看 matchRequest 这个函数

Router.prototype.matchRequest = function(req, i, head){
var method = req.method.toLowerCase()
, url = parse(req)
, path = url.pathname
, routes = this.map
, i = i || 0
, route; // HEAD support
if (!head && 'head' == method) {
route = this.matchRequest(req, i, true);
if (route) return route;
method = 'get';
} // routes for this method
if (routes = routes[method]) { // matching routes
for (var len = routes.length; i < len; ++i) {
route = routes[i];
if (route.match(path)) {
req._route_index = i;
return route;
}
}
}
};

它返回一个路由的处理结果。

后面根据参数执行了param() 函数。这个函数主要是处理callback回调函数的。

2.给路由注册各种函数:

methods.forEach(function(method){
app[method] = function(path){
if ('get' == method && 1 == arguments.length) return this.set(path); // deprecated
if (Array.isArray(path)) {
console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0');
} // if no router attached yet, attach the router
if (!this._usedRouter) this.use(this.router); // setup route
console.log(method,'test2');
this._router[method].apply(this._router, arguments);
return this;
};
});

这个函数直接添加了开始的注册函数,下面的这个methods.foreach 依次为每一个app.get,app.post 等等 添加路由和 callback 函数

Router.prototype.route = function(method, path, callbacks){
var method = method.toLowerCase()
, callbacks = utils.flatten([].slice.call(arguments, 2)); // ensure path was given
if (!path) throw new Error('Router#' + method + '() requires a path'); // ensure all callbacks are functions
callbacks.forEach(function(fn){
if ('function' == typeof fn) return;
var type = {}.toString.call(fn);
var msg = '.' + method + '() requires callback functions but got a ' + type;
throw new Error(msg);
}); // create the route
debug('defined %s %s', method, path);
var route = new Route(method, path, callbacks, {
sensitive: this.caseSensitive,
strict: this.strict
}); // add it
(this.map[method] = this.map[method] || []).push(route);
return this;
}; Router.prototype.all = function(path) {
var self = this;
var args = [].slice.call(arguments);
methods.forEach(function(method){
self.route.apply(self, [method].concat(args));
});
return this;
}; methods.forEach(function(method){
Router.prototype[method] = function(path){
var args = [method].concat([].slice.call(arguments));
this.route.apply(this, args);
return this;
};
});

最后一个函数,直接执行,给路由添加get,post等函数。

在Router.prototype.route  函数中,我们调用了一个:

var route = new Route(method, path, callbacks, {
sensitive: this.caseSensitive,
strict: this.strict
});

Route 是一个路由的基本单元,包含2个方法:

function Route(method, path, callbacks, options) {
options = options || {};
this.path = path;
this.method = method;
this.callbacks = callbacks;
this.regexp = utils.pathRegexp(path
, this.keys = []
, options.sensitive
, options.strict);
} /**
* Check if this route matches `path`, if so
* populate `.params`.
*
* @param {String} path
* @return {Boolean}
* @api private
*/ Route.prototype.match = function(path){
var keys = this.keys
, params = this.params = []
, m = this.regexp.exec(path); if (!m) return false; for (var i = 1, len = m.length; i < len; ++i) {
var key = keys[i - 1]; var val = 'string' == typeof m[i]
? utils.decode(m[i])
: m[i]; if (key) {
params[key.name] = val;
} else {
params.push(val);
}
} return true;
}; 

nodejs express 框架解密4-路由的更多相关文章

  1. nodejs express 框架解密1-总体结构

    本文是基于express3.4.6的. 1.express 代码结构为: bin/express 是在命令行下的生成express 框架目录文件用的 lib/express 是框架的入口文件 lib/ ...

  2. nodejs express 框架解密2-如何创建一个app

    本文是基于express 3.4.6 的 1.在我们的app.js 文件里面有这么几行 http.createServer(app).listen(app.get('port'), function( ...

  3. nodejs express 框架解密5-视图

    本文档是基于express 3.4.6 的 在我们的代码中,渲染模板大致是这样写的 exports.index = function(req, res){ res.render('index', { ...

  4. nodejs express 框架解密3-中间件模块

    本文档是基于express 3.4.6 的 在上篇中我们提到了中间件,这篇主要解释这个模块,middleware.js 为: var utils = require('./utils'); /** * ...

  5. Express框架(http服务器 + 路由)

    index.js 使用express框架搭建http服务器,和实现路由功能. var express = require('express'); var app = express(); // 主页输 ...

  6. React第一篇: 搭建React + nodejs + express框架

    前提: 需要安装Node.js (>6)版本 1.cmd进到本地某个目录, 逐行输入以下指令(以下括号为注释) npm install -g create-react-app   (全局安装cr ...

  7. NodeJs笔记 : express框架创建工程 ----- 路由设计

    一.搭建工程 1 .安装 express-generator $ npm install -g express-generator 2 .本地创建express项目 $ express -e blog ...

  8. nodejs express 框架 上传文件

    web 项目应用express4.0框架 html 表单post 文件上传失败,后端无法获取提交文件 express不支持文件上传. 方式一 若是图片,可以将图片转码为BASE64上传 前端框架ang ...

  9. nodeJS express框架 中文乱码解决办法

    最近在研究javascript 的服务端应用 node,之所以想要研究node,是因为前几个月一直在前端挣扎,从javascript入门到在项目中实际使用javascript,确实感悟颇深.javas ...

随机推荐

  1. log4net详细配置说明

    原文地址:http://blog.sina.com.cn/s/blog_671486bc01011rdj.html 1.概述 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记 ...

  2. Titanium系列--Titanium的简介、Titanium Studio安装和配置(一)

    1. 是什么?--是一个可以通过javascript,html,css等web技术开发移动App的的开发框架,媲美原生App体验和性能,目前支持IOS和Android平台. 2. 为什么能做这个? - ...

  3. SR触发器和JK触发器

    SR触发器(电平触发器) 基本RS触发器的逻辑方程为:Q(n+1)=一S+RQ(n); 约束方程:R+S=1; 根据上述两个式子得到它的四种输入与输出的关系: 1.当R端有效(0),S端无效时(1), ...

  4. WPF ToolKit Chart 自定义样式

    1.引用:WPFToolkit.dll, System.Windows.Controls.DataVisualization.Toolkit.dll 2. 页面代码参考如下: <UserCont ...

  5. 结对实验报告-android计算器设计

     一:引言  目前手机可以说是普及率非常高的电子设备了,由于其便于携带,使用方便,资费适中等等原因,现在手机已经在一定程度开始代替固定电话的通话功能,以及一些原来电脑软件上的功能了.手机上的软件也随着 ...

  6. windows下重启mysql

    其中第二种方法对我这无效,以后再搞清楚! 一.MYSQL服务 我的电脑——(右键)管理——服务与应用程序——服务——MYSQL——开启(停止.重启动) 二.命令行方式 Windows 1.点击“开始” ...

  7. 某些版本的IIS可能有SessionID混淆的Bug

    某公司为我服务的甲方公司开发一个挺重要的应用.已经上线了一年多了,不停的修修改改.也算正常使用.正所谓,秀恩爱,死得快.No 作就No Die.也少知道是那个Smarty Pants闲的蛋疼说新修改的 ...

  8. ubuntu 12.04 支持中文----完胜版

    原文地址 http://pobeta.com/ubuntu-sublime.html, /* sublime-imfix.c Use LD_PRELOAD to interpose some func ...

  9. Spring声明式事务配置与使用

    1.配置: <context:component-scan base-package="com.vrvwh.wh01" /><bean id="data ...

  10. JfreeChart使用(转载)

    http://www.cnblogs.com/xingyun/ http://www.huosen.net/archives/156.html(此篇除了struts2外,还介绍了servlet下Jfr ...