Writing middleware for use in Express apps

Overview

中间件功能是可以访问请求对象req ), 响应对象res )和应用程序的请求-响应周期中的next功能的功能. next功能是Express路由器中的功能,该功能在被调用时将在当前中间件之后执行中间件.

中间件功能可以执行以下任务:

如果当前中间件函数没有结束请求-响应周期,则它必须调用next()将控制权传递给下一个中间件函数. 否则,该请求将被挂起.

下图显示了中间件函数调用的元素:

中间件功能适用的HTTP方法.
中间件功能适用的路径(路由).
中间件功能.
中间件函数的回调参数,按照惯例称为" next".
中间件函数的HTTP 响应参数,按照惯例称为" res".
中间件功能的HTTP 请求参数,按照惯例称为" req".

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

Example

这是一个简单的" Hello World" Express应用程序的示例. 本文的其余部分将定义三个中间件功能并将其添加到应用程序中:一个名为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"的中间件功能的简单示例. 当对应用程序的请求通过时,此功能仅显示"已记录". 中间件函数被分配给名为myLogger的变量.

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

注意上面对next()的调用. 调用此函数将调用应用程序中的下一个中间件函数. next()函数不是Node.js或Express API的一部分,而是传递给中间件函数的第三个参数. next()函数可以命名为任何名称,但按照惯例,它始终命名为" next". 为避免混淆,请始终使用此约定.

要加载中间件函数,请调用app.use() ,指定中间件函数. 例如,以下代码在路由到根路径(/)之前加载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)

每次应用收到请求时,它将消息" LOGGED"打印到终端.

中间件加载的顺序很重要:首先加载的中间件功能也将首先执行.

如果myLogger在到根路径的路由之后加载,则该请求将永远不会到达它,并且该应用不会显示" LOGGED",因为根路径的路由处理程序会终止请求-响应周期.

中间件函数myLogger仅打印一条消息,然后通过调用next()函数将请求传递到堆栈中的下一个中间件函数.

Middleware function requestTime

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

var requestTime = function (req, res, next) {
  req.requestTime = Date.now()
  next()
}

该应用程序现在使用requestTime中间件功能. 而且,根路径路由的回调函数使用中间件函数添加到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)

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

Middleware function 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在被拒绝时将自动触发我们的错误处理程序.

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)

注意如何next()之后被调用await cookieValidator(req.cookies) 这样可以确保如果cookieValidator解析,则将调用堆栈中的下一个中间件. 如果将任何内容传递给next()函数(字符串'route''router'除外),Express都会将当前请求视为错误,并将跳过所有剩余的无错误处理的路由和中间件函数.

因为您可以访问请求对象,响应对象,堆栈中的下一个中间件功能以及整个Node.js API,所以中间件功能的可能性是无限的.

For more information about Express middleware, see: Using Express middleware.

Configurable middleware

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

File: my-middleware.js

module.exports = function (options) {
  return function (req, res, next) {
    // Implement the middleware function based on the options object
    next()
  }
}

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

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

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

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

by  ICOPY.SITE