_express.js_做爲_Node.js_的老牌框架,是現有框架中最全面的。然而在學習express除了那些api以外,對於框架最重要的就是__中間件__這個概念了。若是理解了,就能夠把這個框架玩活了,項目開發確定會更加順利,並且還能夠開發不少額外的功能,甚至中間件擴展開發。javascript
可是就這麼一個東西,是不少學習node.js的小萌新們就算寫出一個博客項目,都不知道它到底有啥做用。我當時在理解的時候也花了很多功夫,趁着沒有啥工做,給各位學習express.js的一點點個人指導意見。固然,這裏面可能也有koa2和egg的忠實粉絲,但其實全部node框架貌似都有這個概念,因此我用express舉例子,但願各位將就一下哈,應該都是能夠看得懂的。java
首先我先來一波官方的解釋:node
好吧,被這些英語嚇到了,來一波譯文:express
[中間件函數是能夠訪問請求對象(req)、響應對象(res)和應用程序請求響應週期中的下一個函數的函數。下一個函數是Express路由器中的一個函數,當調用該函數時,它執行當前中間件以後的中間件。api
中間件功能能夠執行如下任務:bash
終於知道當初的我爲毛剛開始理解的時候很困難了,說實在的看得我真的有懵的。幸虧,我仍是從這個坑爬出來了,我來拉大家一把了。首先咱們不去深究概念,直接上一個代碼塊。服務器
若是咱們啓動服務,訪問'/'路由,會返回"這是一個根路由",訪問router1路由就會獲得這是一個"這是一個router1路由的"的信息。這看起來是一個很簡單的路由查詢,咱們理一下過程,這個請求是如何訪問到這個路由的呢。app
通常來講,一個express框架的項目會寫入不少路由,但各位要注意的是,這個請求並非直接定位到這個路由的,而是一個從上至下匹配的一個過程。框架
有點亂?不要緊咱們看圖koa
咱們看到這幅圖,有一個箭頭,從上到下的。什麼意思呢,若是用戶發了一個這樣的請求
GET '/router7'
那麼他會從第一個開始一個一個去匹配,知道發現有一個路由名和請求方法都一致的路由,就立馬執行裏面的代碼,而且返回一段文字"這是一個router7路由"。這都很好理解,那麼如今我有一個需求,就是無論訪問任何一個路由,我都要知道這個訪問者的ip地址和訪問的目標路由打印出來,生產訪問日誌。那麼怎麼作了。
咱們分析一波,這段程序是全部的請求都要執行的,若是按照執行順序的說法,那麼這段程序是應該放到全部路由的最前面的,也就是說這段程序是全部路由要通過的一段程序,也就是咱們所說的中間件。好的,廢話很少說,上代碼
const fs = require('fs') const log = (req,res) => { const ip = req.ip, route = req.route.path const log = `ip:${ip} path:${route}` fs.writeFileSync(__dirname + '/log',log) }
好比如今我有一個log函數,它專門用來記錄訪問日誌的。如何全部的都一塊兒執行了,咱們加一段這樣的代碼
app.use(log)
它加在全部代碼的最上面,可是不是加上就完事了,還必須在log函數裏面再加一段代碼,否則當程序執行到裏面以後就出不去了,什麼代碼了。咱們重寫log函數
const log = (req,res,next) => { const ip = req.ip, route = req.route.path const log = `ip:${ip} path:${route}` fs.writeFileSync(__dirname + '/log',log) next() }
你們有沒有看見那個next,它有什麼做用了。前面咱們提到,它其實就是一個過渡者,主要的做用其實就是通過以後,要繼續往下面執行,仍是就此終止返回結果。
說的簡單一點,就是咱們一個http請求,到達咱們的node服務器以後,要經歷的過程,而每通過一個程序塊,就是個中間件,每個中間件只要有next就會傳遞到下一個中間件裏面,直到服務器res響應結果,整個路由就此結束。
咱們整合一下代碼。而且精簡一下,也跑一遍程序
const express = require('express') const app = express() const log = (req,res,next) => { const ip = req.ip, route = req.route.path const log = `ip:${ip} path:${route}` fs.writeFileSync(__dirname + '/log',log) next() } app.use(log)//任何請求都會通過這個log中間件 app.get('/', (req, res) => { console.log(req.route.stack) res.send('這是一個根路由!') }) app.get('/router1', (req, res) => { res.send('這是一個router1路由!') }) app.get('/router2', (req, res) => { res.send('這是一個router2路由!') }) app.listen(3000, () => { console.log('app listening on port 3000!') })
GET '/router2' //打印日誌,而且返回結果
這就是一個簡單的中間件解釋了。你們也能夠回去看看你原來寫過的代碼,是否對以前的use這個玩意有點啓發了?
我是小龍,但願對你們有所幫助