express是當下最熱門的基於node.js 的web框架,它提供了一系列強大的特性:node
本文主要介紹路由及中間件!git
首先咱們要知道,express路由的使用方法github
app.get('/', function (req, res, next) {
console.log(1);
next();
}, function (req, res, next) {
console.log(11);
next();
})
app.get('/2', function (req, res, next) {
console.log(2);
next();
}, function (req, res, next) {
console.log(3)
next()
})
-
複製代碼
上述代碼可見,咱們發現有幾個特色:web
* 路由的處理函數能夠有多個;
* 路由的註冊也能夠有多個;
* 調用next進入下一個處理函數或路由;
複製代碼
下邊咱們就來看下express是如何註冊路由的:express
源碼目錄:npm
首先在express.js源碼中咱們能夠看到這樣一句,說明app類繼承proto(即application.js)bash
var proto = require('./application');
mixin(app, proto, false);
複製代碼
接着進入application中看到這樣一個方法,而且在源碼中屢次調用;app
// 看名字咱們就知道這個是用來加載router的;而且將新建的router實例綁定到了this._router屬性上;
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));
}
};
複製代碼
接着下邊看到這樣的一段代碼;框架
// methods實際上是一個npm的包啦,包含了通用的method類型:get、post等
// 下邊代碼能夠看出循環在app中添加了多個屬性get、post。。。
// 而且關鍵的是調用 app.get(); 函數體中實際是調用了this._router.get()
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);
route[method].apply(route, slice.call(arguments, 1));
return this;
};
})
// 代碼中能夠看到
複製代碼
下邊就是路由的重頭戲了,進入到咱們的Router文件中;函數
methods.concat('all').forEach(function(method){
proto[method] = function(path){
var route = this.route(path)
// 最終調用的get方法
route[method].apply(route, slice.call(arguments, 1));
return this;
};
});
* 看到這段代碼是否是很熟悉,在application文件中有相似的代;那麼這個就不難理解,在proto屬性上添加了get、post等屬性
* proto又是什麼呢,往上翻一下就能夠看到啦,其實就是導出對象,而且將全部的屬性繼承到了router方法上
* 這樣咱們就不難聯想到,在application中調用的get方法實際上是調用這裏的get,那麼咱們來看它又作了什麼; 它調用了this.route方法
proto.route = function route(path) {
var route = new Route(path);
var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: this.strict,
end: true
}, route.dispatch.bind(route));
layer.route = route;
this.stack.push(layer);
return route;
};
* 在route方法中新建了一個Route的實例(route)和一個Layer的實例(layer),
* 將route掛載到layer上,
* 將layer添加到Router的stack中
* 最後導出route
上述代碼分析能夠知道,在router上添加了一個layer(層),在layer存了一個route;而且Router中的get並非最後的get方法
複製代碼
最後咱們進入route文件中揭開路由的廬山真面目;
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];
var layer = Layer('/', {}, handle);
layer.method = method;
this.methods[method] = true;
this.stack.push(layer);
}
return this;
};
});
* 仍是一樣的配方(methods),在route類的原型上添加了get、post等方法
* 調用get等方法,根據傳遞handle方法的數量循環在route的stack中添加多個層,每一個方法對應一個層
複製代碼
結果大概是什麼樣的?
說到路由調用express既然是http框架,那麼確定是要先找到這段代碼;
-- application.js --
app.listen = function listen() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
* 熟悉nodejs的你們確定知道 http.createServer()方法中傳入的回調就是請求來時咱們第一次調用的方法
* 那麼只要找到這裏傳入的this就知道是處理請求的第一層調用了;很明顯這裏的this就咱們的app,那app又是什麼呢?下邊的代碼就告訴了咱們;
-- express.js --
var app = function(req, res, next) {
app.handle(req, res, next);
};
* 看到這裏發現調用app方法,會調用app.handle()
-- application.js --
app.handle = function handle(req, res, callback) {
var router = this._router;
var done = callback || finalhandler(req, res, {
env: this.get('env'),
onerror: logerror.bind(this)
});
if (!router) {
debug('no routes defined on app');
done();
return;
}
router.handle(req, res, done);
};
* 在app.handle()方法中看到會調用this._router.handle,this._router相信你們都沒有忘記;
複製代碼
router及route中handle處理請看下圖:
若有問題,但願你們給予指正~!