使用中间件

¥Using middleware

Express 是一个路由和中间件 Web 框架,其自身功能最少:Express 应用本质上是一系列中间件函数调用。

¥Express is a routing and middleware web framework that has minimal functionality of its own: An Express application is essentially a series of middleware function calls.

中间件函数是可以访问 请求对象 (req)、响应对象 (res) 以及应用请求-响应周期中的下一个中间件函数的函数。下一个中间件函数通常由一个名为 next 的变量表示。

¥Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.

中间件函数可以执行以下任务:

¥Middleware functions can perform the following tasks:

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

¥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.

Express 应用可以使用以下类型的中间件:

¥An Express application can use the following types of middleware:

你可以使用可选的挂载路径加载应用级和路由级中间件。你还可以将一系列中间件函数一起加载,从而在挂载点创建中间件系统的子堆栈。

¥You can load application-level and router-level middleware with an optional mount path. You can also load a series of middleware functions together, which creates a sub-stack of the middleware system at a mount point.

应用级中间件

使用 app.use()app.METHOD() 函数将应用级中间件绑定到 应用对象 的实例,其中 METHOD 是中间件函数处理的请求的 HTTP 方法(例如 GET、PUT 或 POST),小写。

¥Bind application-level middleware to an instance of the app object by using the app.use() and app.METHOD() functions, where METHOD is the HTTP method of the request that the middleware function handles (such as GET, PUT, or POST) in lowercase.

此示例显示了一个没有挂载路径的中间件函数。每次应用收到请求时都会执行该函数。

¥This example shows a middleware function with no mount path. The function is executed every time the app receives a request.

const express = require('express')
const app = express()

app.use((req, res, next) => {
  console.log('Time:', Date.now())
  next()
})

这个例子展示了一个挂载在 /user/:id 路径上的中间件函数。该函数针对 /user/:id 路径上的任何类型的 HTTP 请求执行。

¥This example shows a middleware function mounted on the /user/:id path. The function is executed for any type of HTTP request on the /user/:id path.

app.use('/user/:id', (req, res, next) => {
  console.log('Request Type:', req.method)
  next()
})

这个例子展示了一个路由和它的处理函数(中间件系统)。该函数处理对 /user/:id 路径的 GET 请求。

¥This example shows a route and its handler function (middleware system). The function handles GET requests to the /user/:id path.

app.get('/user/:id', (req, res, next) => {
  res.send('USER')
})

这是一个在挂载点加载一系列中间件函数的示例,带有挂载路径。它说明了一个中间件子堆栈,它将任何类型的 HTTP 请求的请求信息打印到 /user/:id 路径。

¥Here is an example of loading a series of middleware functions at a mount point, with a mount path. It illustrates a middleware sub-stack that prints request info for any type of HTTP request to the /user/:id path.

app.use('/user/:id', (req, res, next) => {
  console.log('Request URL:', req.originalUrl)
  next()
}, (req, res, next) => {
  console.log('Request Type:', req.method)
  next()
})

路由处理程序使你能够为路径定义多个路由。下面的示例定义了两条到 /user/:id 路径的 GET 请求路由。第二个路由不会引起任何问题,但它永远不会被调用,因为第一个路由结束了请求-响应周期。

¥Route handlers enable you to define multiple routes for a path. The example below defines two routes for GET requests to the /user/:id path. The second route will not cause any problems, but it will never get called because the first route ends the request-response cycle.

此示例显示了一个处理对 /user/:id 路径的 GET 请求的中间件子堆栈。

¥This example shows a middleware sub-stack that handles GET requests to the /user/:id path.

app.get('/user/:id', (req, res, next) => {
  console.log('ID:', req.params.id)
  next()
}, (req, res, next) => {
  res.send('User Info')
})

// handler for the /user/:id path, which prints the user ID
app.get('/user/:id', (req, res, next) => {
  res.send(req.params.id)
})

要跳过路由中间件堆栈中的其余中间件函数,请调用 next('route') 将控制权传递给下一个路由。注意:next('route') 将仅在使用 app.METHOD()router.METHOD() 函数加载的中间件函数中工作。

¥To skip the rest of the middleware functions from a router middleware stack, call next('route') to pass control to the next route. NOTE: next('route') will work only in middleware functions that were loaded by using the app.METHOD() or router.METHOD() functions.

此示例显示了一个处理对 /user/:id 路径的 GET 请求的中间件子堆栈。

¥This example shows a middleware sub-stack that handles GET requests to the /user/:id path.

app.get('/user/:id', (req, res, next) => {
  // if the user ID is 0, skip to the next route
  if (req.params.id === '0') next('route')
  // otherwise pass the control to the next middleware function in this stack
  else next()
}, (req, res, next) => {
  // send a regular response
  res.send('regular')
})

// handler for the /user/:id path, which sends a special response
app.get('/user/:id', (req, res, next) => {
  res.send('special')
})

中间件也可以在数组中声明以实现可重用性。

¥Middleware can also be declared in an array for reusability.

此示例显示了一个带有中间件子堆栈的数组,用于处理对 /user/:id 路径的 GET 请求

¥This example shows an array with a middleware sub-stack that handles GET requests to the /user/:id path

function logOriginalUrl (req, res, next) {
  console.log('Request URL:', req.originalUrl)
  next()
}

function logMethod (req, res, next) {
  console.log('Request Type:', req.method)
  next()
}

const logStuff = [logOriginalUrl, logMethod]
app.get('/user/:id', logStuff, (req, res, next) => {
  res.send('User Info')
})

路由级中间件

路由级中间件的工作方式与应用级中间件相同,只是它绑定到 express.Router() 的实例。

¥Router-level middleware works in the same way as application-level middleware, except it is bound to an instance of express.Router().

const router = express.Router()

使用 router.use()router.METHOD() 函数加载路由级中间件。

¥Load router-level middleware by using the router.use() and router.METHOD() functions.

以下示例代码通过使用路由级中间件复制了上面显示的应用级中间件的中间件系统:

¥The following example code replicates the middleware system that is shown above for application-level middleware, by using router-level middleware:

const express = require('express')
const app = express()
const router = express.Router()

// a middleware function with no mount path. This code is executed for every request to the router
router.use((req, res, next) => {
  console.log('Time:', Date.now())
  next()
})

// a middleware sub-stack shows request info for any type of HTTP request to the /user/:id path
router.use('/user/:id', (req, res, next) => {
  console.log('Request URL:', req.originalUrl)
  next()
}, (req, res, next) => {
  console.log('Request Type:', req.method)
  next()
})

// a middleware sub-stack that handles GET requests to the /user/:id path
router.get('/user/:id', (req, res, next) => {
  // if the user ID is 0, skip to the next router
  if (req.params.id === '0') next('route')
  // otherwise pass control to the next middleware function in this stack
  else next()
}, (req, res, next) => {
  // render a regular page
  res.render('regular')
})

// handler for the /user/:id path, which renders a special page
router.get('/user/:id', (req, res, next) => {
  console.log(req.params.id)
  res.render('special')
})

// mount the router on the app
app.use('/', router)

要跳过路由的其余中间件函数,请调用 next('router') 将控制权从路由实例传回。

¥To skip the rest of the router’s middleware functions, call next('router') to pass control back out of the router instance.

此示例显示了一个处理对 /user/:id 路径的 GET 请求的中间件子堆栈。

¥This example shows a middleware sub-stack that handles GET requests to the /user/:id path.

const express = require('express')
const app = express()
const router = express.Router()

// predicate the router with a check and bail out when needed
router.use((req, res, next) => {
  if (!req.headers['x-auth']) return next('router')
  next()
})

router.get('/user/:id', (req, res) => {
  res.send('hello, user!')
})

// use the router and 401 anything falling through
app.use('/admin', router, (req, res) => {
  res.sendStatus(401)
})

错误处理中间件

错误处理中间件总是需要四个参数。你必须提供四个参数以将其标识为错误处理中间件函数。即使你不需要使用 next 对象,你也必须指定它来维护签名。否则,next 对象将被解释为常规中间件,无法处理错误。

¥Error-handling middleware always takes four arguments. You must provide four arguments to identify it as an error-handling middleware function. Even if you don’t need to use the next object, you must specify it to maintain the signature. Otherwise, the next object will be interpreted as regular middleware and will fail to handle errors.

以与其他中间件函数相同的方式定义错误处理中间件函数,除了使用四个参数而不是三个参数,特别是使用签名 (err, req, res, next)):

¥Define error-handling middleware functions in the same way as other middleware functions, except with four arguments instead of three, specifically with the signature (err, req, res, next)):

app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

有关错误处理中间件的详细信息,请参见:错误处理

¥For details about error-handling middleware, see: Error handling.

内置中间件

从版本 4.x 开始,Express 不再依赖 Connect。以前包含在 Express 中的中间件函数现在位于单独的模块中;见 中间件函数列表

¥Starting with version 4.x, Express no longer depends on Connect. The middleware functions that were previously included with Express are now in separate modules; see the list of middleware functions.

Express 具有以下内置中间件函数:

¥Express has the following built-in middleware functions:

第三方中间件

使用第三方中间件向 Express 应用添加功能。

¥Use third-party middleware to add functionality to Express apps.

安装所需功能的 Node.js 模块,然后在应用级别或路由级别将其加载到你的应用中。

¥Install the Node.js module for the required functionality, then load it in your app at the application level or at the router level.

以下示例说明了安装和加载 cookie 解析中间件函数 cookie-parser

¥The following example illustrates installing and loading the cookie-parsing middleware function cookie-parser.

$ npm install cookie-parser
const express = require('express')
const app = express()
const cookieParser = require('cookie-parser')

// load the cookie-parsing middleware
app.use(cookieParser())

Express 常用的第三方中间件函数的部分列表,请参见:第三方中间件

¥For a partial list of third-party middleware functions that are commonly used with Express, see: Third-party middleware.