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:中间件功能可以执行以下任务:

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:下图显示了中间件函数调用的元素:

Elements of a middleware function call
HTTP method for which the middleware function applies.应用中间件功能的HTTP方法。
Path (route) for which the middleware function applies.中间件功能应用的路径(路由)。
The middleware function.中间件功能。
Callback argument to the middleware function, called "next" by convention.中间件函数的callback参数,按照惯例称为“next”。
HTTP response argument to the middleware function, called "res" by convention.中间件函数的HTTP响应参数,按照惯例称为“res”。
HTTP request argument to the middleware function, called "req" by convention.中间件函数的HTTP请求参数,按照惯例称为“req”。

Starting with Express 5, middleware functions that return a Promise will call next(value) when they reject or throw an error. next will be called with either the rejected value or the thrown Error.从Express 5开始,返回Promise的中间件函数在拒绝或抛出错误时将调用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.这是一个名为“myLogger”的中间件函数的简单示例。当应用程序收到请求时,此函数只会打印“LOGGED”。中间件函数被分配给一个名为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 to the request object.接下来,我们将创建一个名为“requestTime”的中间件函数,并将名为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-sessioncompression