express.js框架中間件(middleware)

express.js框架中間件(middleware)

_express.js_做爲_Node.js_的老牌框架,是現有框架中最全面的。然而在學習express除了那些api以外,對於框架最重要的就是__中間件__這個概念了。若是理解了,就能夠把這個框架玩活了,項目開發確定會更加順利,並且還能夠開發不少額外的功能,甚至中間件擴展開發。javascript

可是就這麼一個東西,是不少學習node.js的小萌新們就算寫出一個博客項目,都不知道它到底有啥做用。我當時在理解的時候也花了很多功夫,趁着沒有啥工做,給各位學習express.js的一點點個人指導意見。固然,這裏面可能也有koa2和egg的忠實粉絲,但其實全部node框架貌似都有這個概念,因此我用express舉例子,但願各位將就一下哈,應該都是能夠看得懂的。java

首先我先來一波官方的解釋:node

clipboard.png

好吧,被這些英語嚇到了,來一波譯文:express

[中間件函數是能夠訪問請求對象(req)、響應對象(res)和應用程序請求響應週期中的下一個函數的函數。下一個函數是Express路由器中的一個函數,當調用該函數時,它執行當前中間件以後的中間件。api

中間件功能能夠執行如下任務:bash

  • 執行任何代碼
  • 對請求和響應對象進行更改。
  • 結束請求響應週期。
  • 調用堆棧中的下一個中間件。

終於知道當初的我爲毛剛開始理解的時候很困難了,說實在的看得我真的有懵的。幸虧,我仍是從這個坑爬出來了,我來拉大家一把了。首先咱們不去深究概念,直接上一個代碼塊。服務器

clipboard.png

若是咱們啓動服務,訪問'/'路由,會返回"這是一個根路由",訪問router1路由就會獲得這是一個"這是一個router1路由的"的信息。這看起來是一個很簡單的路由查詢,咱們理一下過程,這個請求是如何訪問到這個路由的呢。app

通常來講,一個express框架的項目會寫入不少路由,但各位要注意的是,這個請求並非直接定位到這個路由的,而是一個從上至下匹配的一個過程。框架

有點亂?不要緊咱們看圖koa

clipboard.png

咱們看到這幅圖,有一個箭頭,從上到下的。什麼意思呢,若是用戶發了一個這樣的請求

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這個玩意有點啓發了?

我是小龍,但願對你們有所幫助

相關文章
相關標籤/搜索