Express和Koa是目前最主流的基於node的web開發框架,他們的開發者是同一班人馬。貌似如今Koa更加流行,可是仍然有大量的項目在使用Express,因此我想經過這篇文章說說Express中間件的原理。html
中間件的本質就是一個函數,在收到請求和返回相應的過程當中作一些咱們想作的事情。Express文檔中對它的做用是這麼描述的:node
執行任何代碼。
修改請求和響應對象。
終結請求-響應循環。
調用堆棧中的下一個中間件。
git
Express文檔中把他們分爲了五類,可是他們的原理相同,只是用法不一樣:github
應用級中間件
路由級中間件
錯誤處理中間件
內置中間件
第三方中間件
web
首先咱們看看中間件的用法:express
var express = require('express')
var app = express();
app.use('/user', function (req, res, next) {
//TODO
next();
});
app.listen(8080)
複製代碼
接下來咱們對比看一下下源碼:api
先看express.js的代碼:數組
這部分代碼中最重要的是紅色方框部分,mixin
是一個第三方庫。能夠簡單理解爲繼承(實際上它不是繼承而是混合)。
bash
接下來咱們看application.js:app
我把文件下載下來而且刪去了註釋,經過這張圖咱們能夠看出這個文件的做用是掛載了全部的方法(包括use等關鍵api)。
這裏面比較重要的是use
方法,它的做用就是把咱們用app.use
註冊的全部中間件和路由方法交給Router
類來處理。
那咱們再看看router文件夾類的結構:
index.js是入口文件,處理全部的路由;
layer.js中聲明瞭Layer
類,處理每一層路由中間件或者每個子中間件;
router.js中聲明瞭Router
類,處理每個子路由。
這裏面有一個子中間件的概念,對應Exprees文檔中有這一句話:
另外,你還能夠同時裝載一系列中間件函數,從而在一個掛載點上建立一個子中間件棧。
這句話的意思是說咱們能夠把代碼寫成下面這種形式:
app.use('/user1', function fn1(req, res, next) {
// TODO
next();
}, function fn2(req, res, next) {
//TODO
next();
});
app.use('/user2', function fn3(req, res, next) {
// TODO
next();
}, function fn4(req, res, next) {
//TODO
next();
});
複製代碼
上面的代碼給user1和user2分別建立了一個子中間件棧。這種語法的實現就是靠Layer
類實現的。
畫一張圖來解釋上面的代碼:
解釋一下上面的代碼和圖:
咱們寫了兩個路由/user1和/user2,每一個路由給了兩個處理函數。對於這段代碼,Express是這樣處理的:
stack
數組,接下來會建立兩個Layer
放到這個stack
中。stack
和fn一、fn2兩個Layer
。Layer
裏的函數,對應到圖上就是從上至下、從左至右的依次執行,順序爲fn一、fn二、fn三、fn4。以上就是Express中間件的簡單原理,白話較多,若是寫的不許確的地方,但願你們批評指正。