编写错误处理程序

中英双语

以与其他中间件函数相同的方式定义错误处理中间件函数,除了错误处理函数有四个参数而不是三个:(err, req, res, next)。例如:

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

在其他 app.use() 和路由调用之后,您最后定义错误处理中间件;例如:

const bodyParser = require('body-parser')
const methodOverride = require('method-override')

app.use(bodyParser.urlencoded({
  extended: true
}))
app.use(bodyParser.json())
app.use(methodOverride())
app.use((err, req, res, next) => {
  // logic
})

来自中间件函数的响应可以是任何格式,例如 HTML 错误页面、简单消息或 JSON 字符串。

出于组织(和更高级别的框架)的目的,您可以定义几个错误处理中间件函数,就像您使用常规中间件函数一样。例如,为使用 XHR 和不使用 XHR 发出的请求定义错误处理程序:

const bodyParser = require('body-parser')
const methodOverride = require('method-override')

app.use(bodyParser.urlencoded({
  extended: true
}))
app.use(bodyParser.json())
app.use(methodOverride())
app.use(logErrors)
app.use(clientErrorHandler)
app.use(errorHandler)

在此示例中,通用 logErrors 可能会将请求和错误信息写入 stderr,例如:

function logErrors (err, req, res, next) {
  console.error(err.stack)
  next(err)
}

同样在本例中,clientErrorHandler定义如下;在这种情况下,错误会显式传递给下一个错误。

请注意,当不在错误处理函数中调用 "next" 时,您负责编写(和结束)响应。否则,这些请求将 "hang" 并且没有资格进行垃圾收集。

function clientErrorHandler (err, req, res, next) {
  if (req.xhr) {
    res.status(500).send({ error: 'Something failed!' })
  } else {
    next(err)
  }
}

实现 "catch-all" errorHandler 函数如下(例如):

function errorHandler (err, req, res, next) {
  res.status(500)
  res.render('error', { error: err })
}

如果您有一个带有多个回调函数的路由处理程序,您可以使用 route 参数跳到下一个路由处理程序。例如:

app.get('/a_route_behind_paywall',
  (req, res, next) => {
    if (!req.user.hasPaid) {
      // continue handling this request
      next('route')
    } else {
      next()
    }
  }, (req, res, next) => {
    PaidContent.find((err, doc) => {
      if (err) return next(err)
      res.json(doc)
    })
  })

在此示例中,将跳过 getPaidContent 处理程序,但 app 中用于 /a_route_behind_paywall 的任何剩余处理程序将继续执行。

调用 next()next(err) 表示当前处理程序已完成以及处于什么状态。next(err) 将跳过链中所有剩余的处理程序,除了那些设置为如上所述处理错误的处理程序。