hello,小夥伴們,我是大家的pubdreamcc
,本篇博文出至於個人GitHub倉庫node學習教程資料
,歡迎小夥伴們點贊和star
,大家的點贊是我持續更新的動力。javascript
GitHub倉庫地址:node學習教程html
好了,廢話很少說了,今天繼續咱們express
的學習~java
今天咱們來聊一聊express中很是重要的一個概念——express middleware
(express中間件)。中間件實質就是一個函數,咱們從發送一個請求到最後服務端給迴響應,在這個過程當中請求會通過多箇中間件處理。下面給出一張圖來理解express中間件的概念:node
這個是咱們日常自來水的處理過程圖,能夠看到咱們自來水從水庫取出來到最後進入每一個家庭,中間通過了屢次的處理,咱們能夠理解爲中間的每個處理過程(方法)稱之爲中間件。express
中middleware
相似於上圖中的每個處理過程,咱們請求到響應之間也是通過了一個或多箇中間件處理,最後纔是咱們看到的響應結果。git
這裏咱們能夠看下express
官網對中間件的分類介紹。github
express-middlewareexpress
Application-level middleware
(應用程序級別中間件)應用程序級別中間件又分爲如下三種狀況。瀏覽器
const app = express() app.use((req, res, next) => { console.log('請求來了1~') next() // 調用next(),請求會去下一個緊挨着的匹配的中間件 }) app.use((req, res, next) => { console.log('請求來了2~') // 沒有調用next(),請求會留在該中間件中 }) app.use((req, res, next) => { console.log('請求來了3~') })
這裏配置了三個應用程序級別的中間件,當客戶端發一個請求,就會從上至下首先進入第一個中間件處理,接着看是否內部調用next()
來決定請求是否往下執行。服務器
咱們在服務端請求處理函數中還能夠傳入第三個參數:next
,若是在函數體中調用next()
,則請求會在通過該中間件處理後繼續向下找最近的那個匹配成功的中間件,而且進入該中間件處理。若是沒有調用next()
,則請求會留在該中間件中,不會繼續往下執行。cookie
結果:
// 請求來了1 // 請求來了2
const app = express() app.use('/a', (req, res, next) => { console.log('請求來了1~') next() // 調用next(),請求會去下一個緊挨着的匹配的中間件 }) app.use('/b', (req, res, next) => { console.log('請求來了2~') }) app.use('/a', (req, res, next) => { console.log('請求來了3~') })
一樣的,這裏也配置了三個中間件,由於在中間件中規定了請求路徑,因此只能是以 /a
開頭 的請求才能進入第一個中間件處理。由於在第一個中間件內部調用了next()
方法,因此請求會繼續往下找匹配的中間件,第二個中間請求地址不匹配,因此進入第三個中間件處理。
結果:
// 請求來了1 // 請求來了3
對於這種狀況咱們最爲熟悉,以前已經練習過屢次。
const app = express() app.get('/a', (req, res, next) => { console.log('請求來了1~') next() // 調用next(),請求會去下一個緊挨着的匹配的中間件 }) app.post('/a', (req, res, next) => { console.log('請求來了2~') }) app.get('/a', (req, res, next) => { console.log('請求來了3~') })
一樣以上面的例子,寫三個中間件。這裏規定了必須以 GET
請求並且請求路徑爲:/a
的請求會被第一個中間件處理,由於內部調用了 next()
,因此請求會繼續往下找臨近的匹配的中間件,第二個中間件規定的請求方法爲:POST
,因此進入第三個中間件處理。
結果:
// 請求來了1 // 請求來了3
Router-level middleware
(路由級別中間件)路由級別的中間件與上面應用程序級別中間件的工做方式相似,只不過把路由模塊單獨提取出來,最後經過把路由容器掛載到 app
服務器實例上便可。
const router = express.Router() router.use((req, res, next) => { console.log('請求來了1~') next() // 調用next(),請求會去下一個緊挨着的匹配的中間件 }) router.use((req, res, next) => { console.log('請求來了2~') // 沒有調用next(),請求停留在此,不會繼續往下找了 }) router.use((req, res, next) => { console.log('請求來了3~') })
結果:
// 請求來了1~ // 請求來了2~
const router = express.Router() router.use('/a', (req, res, next) => { console.log('請求來了1~') next() // 調用next(),請求會去下一個緊挨着的匹配的中間件 }) router.use('/b', (req, res, next) => { console.log('請求來了2~') }) router.use('/a', (req, res, next) => { console.log('請求來了3~') })
結果:
// 請求來了1~ // 請求來了3~
const router = express.Router() router.get('/a', (req, res, next) => { console.log('請求來了1~') next() // 調用next(),請求會去下一個緊挨着的匹配的中間件 }) router.post('/a', (req, res, next) => { console.log('請求來了2~') }) router.get('/a', (req, res, next) => { console.log('請求來了3~') })
結果:
// 請求來了1~ // 請求來了3~
Error-handling middleware
(全局錯誤處理中間件)在實際開發中,每每咱們須要統一來處理異步操做發生的錯誤,這個時候咱們須要在項目中配置一個全局錯誤處理中間件便可。
const express = require('express') const fs = require('fs') const app = express() app.get('/', (req, res, next) => { fs.readFile('./index.html', (err, date) => { if (err) { // 若是異步讀取文件錯誤,把錯誤對象傳給next() return next(err) } // 成功,發送讀取後的數據,瀏覽器渲染頁面 res.send(data) }) }) // 配置一個全局錯誤處理中間件,注意這裏接收四個參數,一個都不能少,不然會出錯 app.use((err, req, res, next) => { // err參數爲前面next()方法接收到的錯誤對象 res.status(500).send(err.message) })
經過配置一個全局錯誤處理中間件,咱們能夠統一處理請求發送錯誤時服務端的響應。這裏必定要給錯誤處理中間件的處理函數 四個參數, 切記。在應用程序級別的中間件 app.get()
中,當異步讀取文件失敗時,記得要把錯誤對象傳遞給next()
方法 。經過這樣,一旦 index.html
文件丟失,請求則會進入錯誤處理中間件,發送錯誤對象的具體消息給到瀏覽器響應。
Built-in middleware
(內置中間件)express爲咱們也提供了一些內置中間件,好比常見的開放靜態資源: express.static()
等。
const express = require('express') const app = express() // 開放公共資源 app.use('/public/', express.static('./public'))
Third-party middleware
(第三方中間件)一樣,咱們也可使用別人封裝好的第三方中間件,第三方中間件都是一個個第三方包,因此使用前須要咱們單獨下載到項目中。以前的 body-parser
中間件,就是用來解析 post
請求體的數據,還有常見的像 express-session
中間件, cookie-parser
用來獲取請求的cookie
數據等。第三方中間件具體能夠查看 express 官方 API,這裏就再也不一一羅列 。
官方推薦的第三方中間件:第三方中間件
由於文章內容是本身空閒時間編寫,若是您發現有哪些錯誤能夠在GitHub上提交 issue
,也能夠在留言區發表評論,這樣能夠方便於後來的同窗學習,謝謝啦~