总览

中间件功能是可以访问请求对象req),响应对象res)以及next应用程序的请求-响应周期中的功能的功能。该next功能是Express路由器中的功能,当调用该功能时,它会在当前中间件之后执行中间件。
中间件功能可以执行以下任务:

  • 执行任何代码。
  • 更改请求和响应对象。
  • 结束请求-响应周期。
  • 调用堆栈中的下一个中间件。

如果当前中间件功能没有结束请求-响应周期,则必须调用next()将控制权传递给下一个中间件功能。否则,该请求将被挂起。
下图显示了中间件函数调用的元素:

开发中间件 - 图1


中间件功能适用的HTTP方法。
中间件功能适用的路径(路由)。
中间件功能。


中间件函数的回调参数,按照惯例称为“ next”。

中间件函数的HTTP 响应参数,按照惯例称为“ res”。
中间件功能的HTTP 请求参数,按照惯例称为“ req”。

从Express 5开始,返回Promise的中间件函数将next(value)在拒绝或引发错误时调用。next将使用拒绝值或引发的错误来调用。

示例

这是一个简单的“ Hello World” Express应用程序的示例。本文的其余部分将定义并向应用程序添加三个中间件功能:一个名为myLogger打印简单的日志消息,一个称为requestTime显示HTTP请求的时间戳,另一个称为validateCookies验证传入的cookie。

  1. var express = require('express')
  2. var app = express()
  3. app.get('/', function (req, res) {
  4. res.send('Hello World!')
  5. })
  6. app.listen(3000)

中间件myLogger

这是一个称为“ myLogger”的中间件功能的简单示例。当对应用程序的请求通过时,此功能仅显示“已记录”。中间件函数被分配给名为的变量myLogger

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

请注意上面的呼叫next()。调用此函数将调用应用程序中的下一个中间件函数。该next()函数不是Node.js或Express API的一部分,而是传递给中间件函数的第三个参数。该next()函数可以命名为任何东西,但按照惯例,它总是命名为“ next”。为避免混淆,请始终使用此约定。
要加载中间件功能,请调用app.use(),指定中间件功能。例如,以下代码myLogger在路由到根路径(/)之前加载中间件功能。

  1. var express = require('express')
  2. var app = express()
  3. var myLogger = function (req, res, next) {
  4. console.log('LOGGED')
  5. next()
  6. }
  7. app.use(myLogger)
  8. app.get('/', function (req, res) {
  9. res.send('Hello World!')
  10. })
  11. app.listen(3000)

每次应用收到请求时,它将消息“ LOGGED”记录到终端。
中间件加载的顺序很重要:首先加载的中间件功能也将首先执行。
如果myLogger在到达根路径的路由之后加载,则请求永远不会到达请求,并且应用程序不会显示“ LOGGED”,因为根路径的路由处理程序会终止请求-响应周期。
中间件函数myLogger只是打印一条消息,然后通过调用该next()函数将请求传递给堆栈中的下一个中间件函数。

中间件requestTime

接下来,我们将创建一个名为“ requestTime”的中间件函数,并将一个名为的属性添加requestTime 到请求对象。

  1. var requestTime = function (req, res, next) {
  2. req.requestTime = Date.now()
  3. next()
  4. }

该应用程序现在使用requestTime中间件功能。此外,根路径路由的回调函数使用中间件函数添加到的属性req(请求对象)。

  1. var express = require('express')
  2. var app = express()
  3. var requestTime = function (req, res, next) {
  4. req.requestTime = Date.now()
  5. next()
  6. }
  7. app.use(requestTime)
  8. app.get('/', function (req, res) {
  9. var responseText = 'Hello World!<br>'
  10. responseText += '<small>Requested at: ' + req.requestTime + '</small>'
  11. res.send(responseText)
  12. })
  13. app.listen(3000)

现在,当您向应用程序的根目录发出请求时,该应用程序将在浏览器中显示您请求的时间戳。

中间件validateCookies

最后,我们将创建一个中间件功能,该功能验证传入的Cookie并在Cookie无效的情况下发送400响应。
这是一个使用外部异步服务验证Cookie的示例函数。

  1. async function cookieValidator (cookies) {
  2. try {
  3. await externallyValidateCookie(cookies.testCookie)
  4. } catch {
  5. throw new Error('Invalid cookies')
  6. }
  7. }

在这里,我们使用cookie-parser中间件从req对象解析传入的cookie ,并将它们传递给我们的cookieValidator函数。该validateCookies中间件返回一个承诺,在拒绝将自动触发我们的错误处理程序。

  1. var express = require('express')
  2. var cookieParser = require('cookie-parser')
  3. var cookieValidator = require('./cookieValidator')
  4. var app = express()
  5. async function validateCookies (req, res, next) {
  6. await cookieValidator(req.cookies)
  7. next()
  8. }
  9. app.use(cookieParser())
  10. app.use(validateCookies)
  11. // error handler
  12. app.use(function (err, req, res, next) {
  13. res.status(400).send(err.message)
  14. })
  15. app.listen(3000)

注意next()after是如何调用的await cookieValidator(req.cookies)。这确保了如果cookieValidator解决,堆栈中的下一个中间件将被调用。如果您向next()函数传递任何内容(字符串'route'或除外'router'),Express都会将当前请求视为错误,并会跳过所有剩余的无错误处理路由和中间件函数。
因为您可以访问请求对象,响应对象,堆栈中的下一个中间件函数以及整个Node.js API,所以中间件函数的可能性是无限的。
有关Express中间件的更多信息,请参见:使用Express中间件

可配置的中间件

如果您需要可配置的中间件,请导出一个接受选项对象或其他参数的函数,然后再根据输入参数返回中间件实现。
文件: my-middleware.js

  1. module.exports = function (options) {
  2. return function (req, res, next) {
  3. // 根据options配置实施中间件方法
  4. next()
  5. }
  6. }

现在可以如下所示使用中间件。

  1. var mw = require('./my-middleware.js')
  2. app.use(mw({ option1: '1', option2: '2' }))

有关可配置中间件的示例,请参考cookie会话压缩