開發中間件
——編寫用於Express應用程序的中間件
概念
中間件函數是可以訪問請求對象 (req),響應對象(res)以及next應用程序請求 - 響應周期中的函數的函數。該next功能是Express路由器中的一個功能,當被調用時,它將執行當前中間件之后的中間件。
中間件功能可以執行以下任務:
- 執行任何代碼。
- 更改請求和響應對象。
- 結束請求 - 響應周期。
- 調用堆棧中的下一個中間件。
如果當前的中間件函數沒有結束請求 - 響應周期,則必須調用next()以將控制傳遞給下一個中間件函數。否則,請求將被掛起。
下圖顯示了中間件函數調用的元素:

例
以下是一個簡單的“Hello World”Express應用程序示例。本文的其余部分將定義並向應用程序添加兩個中間件函數:一個調用myLogger打印一個簡單的日志消息,另一個調用requestTime,顯示HTTP請求的時間戳。
var express = require('express') var app = express() app.get('/', function (req, res) { res.send('Hello World!') }) app.listen(3000)
中間件功能myLogger
這是一個名為“myLogger”的中間件函數的簡單示例。當對應用程序的請求通過時,此函數只打印“LOGGED”。中間件函數被分配給名為的變量myLogger。
var myLogger = function (req, res, next) { console.log('LOGGED') next() }
注意上面的調用
next()。調用此函數會調用應用程序中的下一個中間件函數。該next()函數不是Node.js或Express API的一部分,而是傳遞給中間件函數的第三個參數。該next()函數可以命名為任何東西,但按照慣例,它總是被命名為“next”。為避免混淆,請始終使用此約定。
要加載中間件功能,請調用app.use(),指定中間件功能。例如,以下代碼myLogger在到根路徑(/)的路由之前加載中間件函數。
var express = require('express') var app = express() var myLogger = function (req, res, next) { console.log('LOGGED') next() } app.use(myLogger) app.get('/', function (req, res) { res.send('Hello World!') }) app.listen(3000)
每次應用程序收到請求時,它都會向終端輸出消息“LOGGED”。
中間件加載的順序很重要:首先加載的中間件函數也會先執行。
如果myLogger在到根路徑的路由之后加載,則請求永遠不會到達它並且應用程序不會打印“LOGGED”,因為根路徑的路由處理程序終止請求 - 響應循環。
中間件函數myLogger只是打印一條消息,然后通過調用該next()函數將請求傳遞給堆棧中的下一個中間件函數。
中間件功能requestTime
接下來,我們將創建一個名為“requestTime”的中間件函數,並將其添加為requestTime 對請求對象調用的屬性。
var requestTime = function (req, res, next) { req.requestTime = Date.now() next() }
該應用程序現在使用requestTime中間件功能。此外,根路徑路由的回調函數使用中間件函數添加的屬性req(請求對象)。
var express = require('express') var app = express() var requestTime = function (req, res, next) { req.requestTime = Date.now() next() } app.use(requestTime) app.get('/', function (req, res) { var responseText = 'Hello World!<br>' responseText += '<small>Requested at: ' + req.requestTime + '</small>' res.send(responseText) }) app.listen(3000)
當您向應用程序的根目錄發出請求時,應用程序現在會在瀏覽器中顯示您的請求的時間戳。
因為您可以訪問請求對象,響應對象,堆棧中的下一個中間件函數以及整個Node.js API,所以中間件函數的可能性是無窮無盡的。
可配置的中間件
如果您需要配置中間件,請導出一個接受選項對象或其他參數的函數,然后根據輸入參數返回中間件實現。
文件: my-middleware.js
module.exports = function(options) { return function(req, res, next) { // Implement the middleware function based on the options object next() } }
現在可以使用中間件,如下所示。
var mw = require('./my-middleware.js') app.use(mw({ option1: '1', option2: '2' }))
使用中間件
Express是一種路由和中間件Web框架,它具有自己的最小功能:Express應用程序本質上是一系列中間件函數調用。
中間件函數是可以訪問請求對象 (req),響應對象(res)以及應用程序的請求 - 響應周期中的下一個中間件函數的函數。下一個中間件函數通常由名為的變量表示next。
中間件功能可以執行以下任務:
- 執行任何代碼。
- 更改請求和響應對象。
- 結束請求 - 響應周期。
- 調用堆棧中的下一個中間件函數。
如果當前的中間件函數沒有結束請求 - 響應周期,則必須調用next()以將控制傳遞給下一個中間件函數。否則,請求將被掛起。
Express應用程序可以使用以下類型的中間件:
您可以使用可選的裝載路徑加載應用程序級和路由器級中間件。您還可以將一系列中間件功能加載在一起,從而在安裝點創建中間件系統的子堆棧。
應用程序級中間件
通過使用和函數將應用程序級中間件綁定到app對象的實例,其中是中間件函數以小寫形式處理的請求的HTTP方法(例如GET,PUT或POST)。app.use()app.METHOD()METHOD
此示例顯示了沒有裝載路徑的中間件功能。每次應用程序收到請求時都會執行該功能。
var app = express() app.use(function (req, res, next) { console.log('Time:', Date.now()) next() })
此示例顯示了/user/:id路徑上安裝的中間件功能。對/user/:id路徑上的任何類型的HTTP請求執行該函數。
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
此示例顯示了路由及其處理函數(中間件系統)。該函數處理對/user/:id路徑的GET請求。
app.get('/user/:id', function (req, res, next) {
res.send('USER')
})
下面是一個使用掛載路徑在掛載點加載一系列中間件函數的示例。它說明了一個中間件子堆棧,它將任何類型的HTTP請求的請求信息打印到/user/:id路徑。
app.use('/user/:id', function (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
路徑處理程序使您可以為路徑定義多個路徑。下面的示例為/user/:id路徑的GET請求定義了兩個路由。第二個路由不會引起任何問題,但它永遠不會被調用,因為第一個路由結束了請求 - 響應周期。
此示例顯示了一個中間件子堆棧,用於處理對/user/:id路徑的GET請求。
app.get('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id)
next()
}, function (req, res, next) {
res.send('User Info')
})
// handler for the /user/:id path, which prints the user ID
app.get('/user/:id', function (req, res, next) {
res.end(req.params.id)
})
要從路由器中間件堆棧中跳過其余的中間件功能,請調用next('route')將控制權傳遞給下一個路由。 注意:next('route')僅適用於使用app.METHOD()或router.METHOD()函數加載的中間件函數。
此示例顯示了一個中間件子堆棧,用於處理對/user/:id路徑的GET請求。
app.get('/user/:id', function (req, res, next) {
// if the user ID is 0, skip to the next route
if (req.params.id === '0') next('route')
// otherwise pass the control to the next middleware function in this stack
else next()
}, function (req, res, next) {
// send a regular response
res.send('regular')
})
// handler for the /user/:id path, which sends a special response
app.get('/user/:id', function (req, res, next) {
res.send('special')
})
路由器級中間件
路由器級中間件的工作方式與應用程序級中間件的工作方式相同,不同之處在於它綁定到的實例express.Router()。
var router = express.Router()
使用router.use()和router.METHOD()函數加載路由器級中間件。
以下示例代碼通過使用路由器級中間件復制上面顯示的應用程序級中間件的中間件系統:
var app = express() var router = express.Router() // a middleware function with no mount path. This code is executed for every request to the router router.use(function (req, res, next) { console.log('Time:', Date.now()) next() }) // a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path router.use('/user/:id', function (req, res, next) { console.log('Request URL:', req.originalUrl) next() }, function (req, res, next) { console.log('Request Type:', req.method) next() }) // a middleware sub-stack that handles GET requests to the /user/:id path router.get('/user/:id', function (req, res, next) { // if the user ID is 0, skip to the next router if (req.params.id === '0') next('route') // otherwise pass control to the next middleware function in this stack else next() }, function (req, res, next) { // render a regular page res.render('regular') }) // handler for the /user/:id path, which renders a special page router.get('/user/:id', function (req, res, next) { console.log(req.params.id) res.render('special') }) // mount the router on the app app.use('/', router)
要跳過路由器中間件的其余功能,請調用next('router') 將控制權交還給路由器實例。
此示例顯示了一個中間件子堆棧,用於處理對/user/:id路徑的GET請求。
var app = express() var router = express.Router() // predicate the router with a check and bail out when needed router.use(function (req, res, next) { if (!req.headers['x-auth']) return next('router') next() }) router.get('/', function (req, res) { res.send('hello, user!') }) // use the router and 401 anything falling through app.use('/admin', router, function (req, res) { res.sendStatus(401) })
錯誤處理中間件
錯誤處理中間件總是需要四個參數。您必須提供四個參數以將其標識為錯誤處理中間件函數。即使您不需要使用該next對象,也必須指定它以保持簽名。否則,該next對象將被解釋為常規中間件,並且將無法處理錯誤。
以與其他中間件函數相同的方式定義錯誤處理中間件函數,除了四個參數而不是三個,特別是簽名(err, req, res, next)):
app.use(function (err, req, res, next) { console.error(err.stack) res.status(500).send('Something broke!') })
內置中間件
從版本4.x開始,Express不再依賴於Connect。之前包含在Express中的中間件功能現在位於單獨的模塊中; 查看中間件功能列表。
Express具有以下內置中間件功能:
- express.static提供靜態資源,如HTML文件,圖像等。
- express.json使用JSON有效負載解析傳入的請求。注意:適用於Express 4.16.0+
- express.urlencoded用URL編碼的有效負載解析傳入的請求。 注意:適用於Express 4.16.0+
第三方中間件
使用第三方中間件為Express應用程序添加功能。
安裝Node.js模塊以獲得所需的功能,然后在應用程序級別或路由器級別將其加載到您的應用程序中。
以下示例說明了安裝和加載cookie解析中間件功能cookie-parser。
$ npm install cookie-parser var express = require('express') var app = express() var cookieParser = require('cookie-parser') // load the cookie-parsing middleware app.use(cookieParser())
