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. 如果当前中间件函数没有结束请求-响应周期,它必须调用next()将控制权传递给下一个中间件函数。Otherwise, the request will be left hanging.否则,请求将挂起。

The following figure shows the 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.中间件函数的回调参数,按约定称为“next”。
HTTP response argument to the middleware function, called "res" by convention.中间件函数的HTTP response参数,按约定称为“res”。
HTTP request argument to the middleware function, called "req" by convention.中间件函数的HTTP request参数,按约定称为“req”。

Starting with Express 5, middleware functions that return a Promise will call next(value) when they reject or throw an error. 从Express5开始,返回承诺的中间件函数在拒绝或抛出错误时将调用next(value)next will be called with either the rejected value or the thrown Error.next将使用拒绝的值或抛出的错误调用。

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。

var express = require('express')
var app = express()

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000)

Middleware function myLogger中间件函数myLogger

Here is a simple example of a middleware function called “myLogger”. 下面是一个名为“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的变量。

var myLogger = function (req, res, next) {
  console.log('LOGGED')
  next()
}

Notice the call above to next(). 注意上面对next()的调用。Calling this function invokes the next middleware function in the app. 调用此函数将调用应用程序中的下一个中间件函数。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或Express 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.为避免混淆,请始终使用此约定。

要从路由中间件堆栈中跳过其余中间件功能,请调用next('route')将控制权传递给下一条路由(相当于调用函数的return语句)。

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中间件函数。

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)

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,则请求永远不会到达它,并且应用程序不会打印“已记录”,因为根路径的路由处理程序会终止请求响应周期。

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中间件功能请求时间

Next, we’ll create a middleware function called “requestTime” and add a property called requestTime to the request object.接下来,我们将创建一个名为“requestTime”的中间件函数,并向请求对象添加一个名为requestTime的属性。

var 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(请求对象)的属性。

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)

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中间件功能验证协议

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中间件返回一个承诺,即拒绝后将自动触发错误处理程序。

var express = require('express')
var cookieParser = require('cookie-parser')
var cookieValidator = require('./cookieValidator')

var app = express()

async function validateCookies (req, res, next) {
  await cookieValidator(req.cookies)
  next()
}

app.use(cookieParser())

app.use(validateCookies)

// error handler
app.use(function (err, req, res, next) {
  res.status(400).send(err.message)
})

app.listen(3000)

Note how next() is called after await cookieValidator(req.cookies). 注意如何在await cookieValidator(req.cookies)之后调用next()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.现在可以使用中间件,如下所示。

var mw = require('./my-middleware.js')

app.use(mw({ option1: '1', option2: '2' }))

Refer to cookie-session and compression for examples of configurable middleware.有关可配置中间件的示例,请参阅cookie会话压缩