node.js - Express 和异步/等待 : shall I wrap the lot with try/catch?

标签 node.js express async-await try-catch

我有以下代码:

app.post('/routes/passwordReset/:userId', async (req, res, next) => {
  var userId = req.params.userId

  let record = (await vars.connection.queryP('SELECT * FROM contacts WHERE id = ?', userId))[0]

  if (!record) {
    res.status(404).send('')
    return
  }

  // Calculate token and expiry, update database
  var token = require('crypto').randomBytes(48).toString('base64').replace(/[^a-zA-Z0-9]/g, '').substr(0, 28)
  var now = new Date()
  var inOneHour = new Date(now.getTime() + (1 * 1000 * 60 * 60))
  await vars.connection.queryP('UPDATE contacts SET recoverToken = ?, recoverTokenExpiry = ? WHERE id = ?', [ token, inOneHour, userId ])
  res.status(200).send('')
})

如果我创建了一个人为错误(例如,recoverTokenExpiry 的字段人为地太短),我最终会得到:

[[12:19:55.649]] [ERROR] (node:11919) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 4): Error: ER_DATA_TOO_LONG: Data too long for column 'recoverToken' at row 1

我以某种方式认为 Express 会在中间件周围进行 try/catch 并在抛出错误时调用 next(err) 。也许不是这样?

那么,我应该用 try/catch(e) 包装每个路由,如果出现错误则执行 next(e) 吗?

最佳答案

Express 不会为您做任何事情。这是非常简单的骨头。

您有两个选择:

  1. 将所有内容包装在 try-catch
  2. 编写您自己的错误处理中间件,如文档 here 中所示.

调用next()会将reqres传递给堆栈中的下一个中间件。

调用 next(err),或者给它一个 Exception 对象,将调用堆栈中的任何错误中间件。

<小时/>

在自己的文件中定义错误处理程序:

// error-middleware.js

/**
 * Handler to catch `async` operation errors.
 * Reduces having to write `try-catch` all the time.
 */
exports.catchErrors = action => (req, res, next) => action(req, res).catch(next)

/**
 * Show useful information to client in development.
 */
exports.devErrorHandler = (err, req, res, next) => {
  err.stack = err.stack || ''
  const status = err.status || 500
  const error = { message: err.message }
  res.status(status)
  res.json({ status, error })
}

然后将密码重置逻辑从 app.post 移出并移至其自己的专用函数中:

// password-controller.js

exports.resetPassword = async (req, res) => {
  // do work
  // ...
}

这使得编写单元测试变得更加容易,并且可以清晰地分离关注点。

接下来创建您的密码重置路线:

// password-reset-routes.js

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

const passwordController = require('./password-controller')
const { catchErrors } = require('./error-middleware')

router.post('/routes/passwordReset/:userId', catchErrors(passwordController.resetPassword))

module.exports = router

请注意,上面定义的 Controller 已在此处导入并使用。此外,您还可以看到 Controller 操作 resetPassword 包含有 catchErrors。这避免了一直编写 try-catch ,并且任何错误都将被 catchErrors 中间件捕获。

最后,将其全部连接到您的主 app.js 文件中:

// app.js

const express = require('express')
const { devErrorHandler } = require('./error-middleware')
const passwordResetRoutes = require('./password-reset-routes.js')
const app = express()

app.use(devErrorHandler)
app.use(passwordResetRoutes)

module.exports = app

关于node.js - Express 和异步/等待 : shall I wrap the lot with try/catch?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49664134/

相关文章:

node.js - 类型错误 : require(. ..) 不是 SendGrid NodeJS 中的函数

node.js - 运行 npm 脚本时 npm 使用哪个 shell?

node.js - $ npm install https ://registry. npmjs.org/npm/-/npm-1.3.19.tgz 不喜欢错误

node.js - 如何授权访问 Google Cloud Function 中的 Directory API

node.js - 如何从 Express 路由中的 URL 获取可选语言参数?

node.js - 如何使用 node-express 将文件发送到 iframe 中?

python - 现在开始异步任务,稍后等待

powershell - 在powershell中获取.Net对象异步方法的结果

c# - 使用 ContinueWith 或 Async-Await 时的不同行为

node.js - 无法在 Linux 中安装和运行我自己的 npm 模块