中間件函式是可以存取 請求物件 (req
)、回應物件 (res
) 以及應用程式請求-回應週期中 next
函式的函式。next
函式是 Express 路由器中的函式,當呼叫時,會執行在目前中間件之後的中間件。
中間件函式可以執行下列任務
如果目前的 middleware 函式並未結束請求-回應循環,它必須呼叫 next()
以將控制權傳遞給下一個 middleware 函式。否則,請求將會懸而未決。
下圖顯示 middleware 函式呼叫的元素
![]() |
middleware 函式適用的 HTTP 方法。
middleware 函式適用的路徑 (路由)。
middleware 函式。
middleware 函式的回呼引數,依慣例稱為「next」。
middleware 函式的 HTTP 回應 引數,依慣例稱為「res」。
middleware 函式的 HTTP 請求 引數,依慣例稱為「req」。
|
從 Express 5 開始,傳回 Promise 的 middleware 函式會在拒絕或擲出錯誤時呼叫 next(value)
。next
會以拒絕的值或擲出的 Error 呼叫。
以下是簡單的「Hello World」Express 應用程式的範例。本文的其餘部分將定義並新增三個 middleware 函式到應用程式:一個稱為 myLogger
,用於列印簡單的記錄訊息;一個稱為 requestTime
,用於顯示 HTTP 請求的時間戳記;一個稱為 validateCookies
,用於驗證輸入的 Cookie。
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(3000)
以下是稱為「myLogger」的 middleware 函式的簡單範例。當請求傳遞至應用程式時,此函式只會列印「LOGGED」。middleware 函式會指定給名為 myLogger
的變數。
const myLogger = function (req, res, next) {
console.log('LOGGED')
next()
}
請注意上面呼叫 next()
的部分。呼叫這個函式會呼叫應用程式中的下一個中間件函式。next()
函式並非 Node.js 或 Express API 的一部分,而是傳遞給中間件函式的第三個引數。next()
函式可以命名為任何名稱,但根據慣例,它總是命名為「next」。為避免混淆,請務必遵循此慣例。
若要載入中間件函式,請呼叫 app.use()
,並指定中間件函式。例如,以下程式碼會在根路徑(/)的路由之前載入 myLogger
中間件函式。
const express = require('express')
const app = express()
const myLogger = function (req, res, next) {
console.log('LOGGED')
next()
}
app.use(myLogger)
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(3000)
每次應用程式收到請求時,它會將訊息「LOGGED」印到終端機。
載入中間件的順序很重要:最先載入的中間件函式也會最先執行。
如果 myLogger
在根路徑的路由之後載入,請求永遠不會到達它,而應用程式也不會印出「LOGGED」,因為根路徑的路由處理常式會終止請求-回應循環。
中間件函式 myLogger
只會印出訊息,然後透過呼叫 next()
函式將請求傳遞給堆疊中的下一個中間件函式。
接下來,我們將建立一個稱為「requestTime」的中間件函式,並將一個稱為 requestTime
的屬性新增到請求物件中。
const requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}
應用程式現在使用 requestTime
中間件函式。此外,根路徑路由的回呼函式使用中間件函式新增到 req
(請求物件)的屬性。
const express = require('express')
const app = express()
const requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}
app.use(requestTime)
app.get('/', (req, res) => {
let responseText = 'Hello World!<br>'
responseText += `<small>Requested at: ${req.requestTime}</small>`
res.send(responseText)
})
app.listen(3000)
當您向應用程式的根目錄發出請求時,應用程式現在會在瀏覽器中顯示您請求的時間戳記。
最後,我們將建立一個中間件函式,用於驗證傳入的 cookie,如果 cookie 無效,則傳送 400 回應。
以下是一個使用外部非同步服務驗證 cookie 的範例函式。
async function cookieValidator (cookies) {
try {
await externallyValidateCookie(cookies.testCookie)
} catch {
throw new Error('Invalid cookies')
}
}
在此,我們使用 cookie-parser
中間件來解析 req
物件中的傳入 cookie,並將它們傳遞給我們的 cookieValidator
函式。validateCookies
中間件會傳回一個 Promise,在拒絕時會自動觸發我們的錯誤處理常式。
const express = require('express')
const cookieParser = require('cookie-parser')
const cookieValidator = require('./cookieValidator')
const app = express()
async function validateCookies (req, res, next) {
await cookieValidator(req.cookies)
next()
}
app.use(cookieParser())
app.use(validateCookies)
// error handler
app.use((err, req, res, next) => {
res.status(400).send(err.message)
})
app.listen(3000)
請注意,next()
會在 await cookieValidator(req.cookies)
之後呼叫。這可確保如果 cookieValidator
解決,堆疊中的下一個中間件將會被呼叫。如果您傳遞任何東西給 next()
函式(除了字串 'route'
或 'router'
),Express 會將目前的請求視為錯誤,並會略過任何剩餘的非錯誤處理路由和中間件函式。
由於您可以存取請求物件、回應物件、堆疊中的下一個中間件函式,以及整個 Node.js API,因此中間件函式的可能性是無窮盡的。
有關 Express 中間件的更多資訊,請參閱:使用 Express 中間件。
如果您需要您的中間件可設定,請匯出一個函式,該函式接受選項物件或其他參數,然後根據輸入參數傳回中間件實作。
檔案:my-middleware.js
module.exports = function (options) {
return function (req, res, next) {
// Implement the middleware function based on the options object
next()
}
}
現在可以使用中間件,如下所示。
const mw = require('./my-middleware.js')
app.use(mw({ option1: '1', option2: '2' }))
請參閱 cookie-session 和 compression 以取得可設定中間件的範例。