为 Express 应用程序编写中间件
概述
中间件函数是能够访问应用程序的请求-响应周期中的 请求对象(req
)、响应对象(res
)以及 next
函数的函数。next
函数是 Express 路由中的一个函数,当被调用时,它将执行当前中间件之后的下一个中间件。
中间件函数可以执行以下任务:
- 执行任何代码。
- 修改请求和响应对象。
- 结束请求-响应周期。
- 调用堆栈中的下一个中间件。
如果当前中间件函数没有结束请求-响应周期,它必须调用 next()
将控制权传递给下一个中间件函数。否则,请求将挂起。
下图展示了中间件函数调用的组成要素:
![]() |
中间件函数适用的 HTTP 方法。
中间件函数适用的路径(路由)。
中间件函数。
中间件函数的回调参数,按照惯例称为“next”。
中间件函数的 HTTP 响应参数,按照惯例称为“res”。
中间件函数的 HTTP 请求参数,按照惯例称为“req”。
|
从 Express 5 开始,返回 Promise 的中间件函数在拒绝(reject)或抛出错误时将调用 next(value)
。next
将以被拒绝的值或抛出的 Error 作为参数被调用。
示例
以下是一个简单的“Hello World”Express 应用程序示例。本文的其余部分将为该应用程序定义并添加三个中间件函数:一个名为 myLogger
,用于打印简单的日志消息;一个名为 requestTime
,用于显示 HTTP 请求的时间戳;以及一个名为 validateCookies
,用于验证传入的 cookie。
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(3000)
中间件函数 myLogger
这是一个名为“myLogger”的中间件函数的简单示例。当应用程序接收到请求并经过此函数时,它会打印“LOGGED”。该中间件函数被赋值给一个名为 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”的中间件函数,并向请求对象添加一个名为 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)
当您向应用程序的根目录发出请求时,应用程序现在会在浏览器中显示您请求的时间戳。
中间件函数 validateCookies
最后,我们将创建一个中间件函数,用于验证传入的 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,当 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)
请注意 await cookieValidator(req.cookies)
之后如何调用 next()
。这确保了如果 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,了解可配置中间件的示例。
编辑此页面