Writing middleware for use in Express apps编写用于Express应用程序的中间件
Overview概述
Middleware functions are functions that have access to the request object (中间件函数是可以访问请求对象(req
), the response object (res
), and the next
function in the application’s request-response cycle. req
)、响应对象(res
)和应用程序请求-响应周期中的next
函数的函数。The next
function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware.next
函数是Express路由器中的一个函数,当被调用时,它将执行当前中间件之后的中间件。
Middleware functions can perform the following tasks:中间件功能可以执行以下任务:
Execute any code.执行任何代码。Make changes to the request and the response objects.对请求和响应对象进行更改。End the request-response cycle.结束请求响应周期。Call the next middleware in the stack.调用堆栈中的下一个中间件。
If the current middleware function does not end the request-response cycle, it must call 如果当前中间件函数没有结束请求-响应周期,则必须调用next()
to pass control to the next middleware function. Otherwise, the request will be left hanging.next()
将控制传递给下一个中间件函数。否则,请求将被搁置。
The following figure shows the elements of a middleware function call:下图显示了中间件函数调用的元素:
![]() |
callback 参数,按照惯例称为“next”。 |
Starting with Express 5, middleware functions that return a Promise will call 从Express 5开始,返回Promise的中间件函数在拒绝或抛出错误时将调用next(value)
when they reject or throw an error. next
will be called with either the rejected value or the thrown Error.next(value)
。next
将使用被拒绝的值或抛出的Error调用。
Example示例
Here is an example of a simple “Hello World” Express application.这是一个简单的“Hello World”Express应用程序的示例。
The remainder of this article will define and add three middleware functions to the application:
one called 本文的其余部分将定义三个中间件函数并将其添加到应用程序中:一个名为myLogger
that prints a simple log message, one called requestTime
that
displays the timestamp of the HTTP request, and one called validateCookies
that validates incoming cookies.myLogger
,用于打印简单的日志消息;一个称为requestTime
,用于显示HTTP请求的时间戳;还有一个称为validateCookies
,用于验证传入的Cookie。
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(3000)
Middleware function myLogger中间件功能myLogger
Here is a simple example of a middleware function called “myLogger”. This function just prints “LOGGED” when a request to the app passes through it. The middleware function is assigned to a variable named 这是一个名为“myLogger”的中间件函数的简单示例。当应用程序收到请求时,此函数只会打印“LOGGED”。中间件函数被分配给一个名为myLogger
.myLogger
的变量。
const myLogger = function (req, res, next) {
console.log('LOGGED')
next()
}
Notice the call above to 请注意上面对next()
. Calling this function invokes the next middleware function in the app.next()
的调用。调用此函数将调用应用程序中的下一个中间件函数。
The next()
function is not a part of the Node.js or Express API, but is the third argument that is passed to the middleware function. next()
函数不是Node.js或Expressneneneba API的一部分,而是传递给中间件函数的第三个参数。The next()
function could be named anything, but by convention it is always named “next”.next()
函数可以命名为任何东西,但按照惯例,它总是被命名为“next”。
To avoid confusion, always use this convention.为避免混淆,请始终使用此惯例。
To load the middleware function, call 要加载中间件函数,请调用app.use()
, specifying the middleware function.app.use()
,指定中间件函数。
For example, the following code loads the 例如,以下代码在路由到根路径(myLogger
middleware function before the route to the root path (/)./
)之前加载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)
Every time the app receives a request, it prints the message “LOGGED” to the terminal.每次应用程序收到请求时,它都会向终端打印消息“LOGGED”。
The order of middleware loading is important: middleware functions that are loaded first are also executed first.中间件加载的顺序很重要:首先加载的中间件功能也会首先执行。
If 如果myLogger
is loaded after the route to the root path, the request never reaches it and the app doesn’t print “LOGGED”, because the route handler of the root path terminates the request-response cycle.myLogger
在路由到根路径后加载,则请求永远不会到达它,应用程序也不会打印“LOGGED”,因为根路径的路由处理程序终止了请求-响应循环。
The middleware function 中间件函数myLogger
simply prints a message, then passes on the request to the next middleware function in the stack by calling the next()
function.myLogger
只是打印一条消息,然后通过调用next()
函数将请求传递给堆栈中的下一个中间件函数。
Middleware function requestTime中间件函数requestTime
Next, we’ll create a middleware function called “requestTime” and add a property called 接下来,我们将创建一个名为“requestTime”的中间件函数,并将名为requestTime
to the request object.requestTime
的属性添加到请求对象中。
const requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}
The app now uses the 该应用程序现在使用requestTime
middleware function. requestTime
中间件功能。Also, the callback function of the root path route uses the property that the middleware function adds to 此外,根路径路由的回调函数使用中间件函数添加到req
(the request object).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)
When you make a request to the root of the app, the app now displays the timestamp of your request in the browser.当您向应用程序的根目录发出请求时,应用程序现在会在浏览器中显示您的请求的时间戳。
Middleware function validateCookies中间件函数validateCookies
Finally, we’ll create a middleware function that validates incoming cookies and sends a 400 response if cookies are invalid.最后,我们将创建一个中间件函数,用于验证传入的Cookie,如果Cookie无效,则发送400响应。
Here’s an example function that validates cookies with an external async service.这是一个使用外部异步服务验证Cookie的示例函数。
async function cookieValidator (cookies) {
try {
await externallyValidateCookie(cookies.testCookie)
} catch {
throw new Error('Invalid cookies')
}
}
Here, we use the 在这里,我们使用cookie-parser
middleware to parse incoming cookies off the req
object and pass them to our cookieValidator
function. cookie-parser
中间件来解析req
对象中的传入cookie,并将其传递给cookieValidator
函数。The validateCookies
middleware returns a Promise that upon rejection will automatically trigger our error handler.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)
Note how 注意next()
is called after await cookieValidator(req.cookies)
. next()
是如何在await cookieValidator(req.cookies)
之后调用的。This ensures that if 这确保了如果cookieValidator
resolves, the next middleware in the stack will get called. cookieValidator
解析,堆栈中的下一个中间件将被调用。If you pass anything to the 如果你向next()
function (except the string 'route'
or 'router'
), Express regards the current request as being an error and will skip any remaining non-error handling routing and middleware functions.next()
函数传递任何内容(字符串'route'
或'router'
除外),Express会将当前请求视为错误,并跳过任何剩余的非错误处理路由和中间件函数。
Because you have access to the request object, the response object, the next middleware function in the stack, and the whole Node.js API, the possibilities with middleware functions are endless.因为您可以访问请求对象、响应对象、堆栈中的下一个中间件函数以及整个Node.js API,所以中间件函数的可能性是无限的。
For more information about Express middleware, see: Using Express middleware.有关Express中间件的更多信息,请参阅:使用Express中间件。
Configurable middleware可配置中间件
If you need your middleware to be configurable, export a function which accepts an options object or other parameters, which, then returns the middleware implementation based on the input parameters.如果您需要中间件可配置,请导出一个接受选项对象或其他参数的函数,然后根据输入参数返回中间件实现。
File: 文件:my-middleware.js
module.exports = function (options) {
return function (req, res, next) {
// Implement the middleware function based on the options object
next()
}
}
The middleware can now be used as shown below.现在可以使用中间件,如下所示。
const mw = require('./my-middleware.js')
app.use(mw({ option1: '1', option2: '2' }))
Refer to cookie-session and compression for examples of configurable middleware.有关可配置中间件的示例,请参阅cookie-session和compression。