Express异步异常处理(Async Error Handler)

Express处理异步异常

Express可以很好的处理同步的异常,即一旦有同步异常 throw err,则自动转化为:

js 复制代码
next(err)

以等待后续处理。

但是异步的异常就没办法自动了。如果没有特殊处理的话,它就直接报错了。

Express官方也提出解决方法了,就是要手动 next(err) 一下:

You must catch errors that occur in asynchronous code invoked by route handlers or middleware and pass them to Express for processing. For example:

javascript 复制代码
app.get('/', (req, res, next) => {
  setTimeout(() => {
    try {
      throw new Error('BROKEN')
    } catch (err) {
      next(err)
    }
  }, 100)
})

The above example uses a try...catch block to catch errors in the asynchronous code and pass them to Express. If the try...catch block were omitted, Express would not catch the error since it is not part of the synchronous handler code.

然而 try ... catch ... 并非唯一可以手动 next(err) 的途径,Promisecatch 也行。当然,Express官方也在下面提供了这一方法

Use promises to avoid the overhead of the try...catch block or when using functions that return promises. For example:

javascript 复制代码
app.get('/', (req, res, next) => {
  Promise.resolve().then(() => {
    throw new Error('BROKEN')
  }).catch(next) // Errors will be passed to Express.
})

Since promises automatically catch both synchronous errors and rejected promises, you can simply provide next as the final catch handler and Express will catch errors, because the catch handler is given the error as the first argument.

理论可行,那么就开始封装吧

封装

StackOverflow 中,Marcos Casagrande 的帖子 "Handling errors in express async middleware" (Jul 2018) 完美封装了这个异步异常处理器。感兴趣的朋友可以点击链接去看看。

以下是我对这个封装的理解:

首先 Mr.Casagrande 的代码如下:

js 复制代码
const asyncHandler = fn => (req, res, next) => {
    return Promise
        .resolve(fn(req, res, next))
        .catch(next);
};

module.exports = asyncHandler;

如果 fn 正常运行了,那么 catch 会 catch 个寂寞,从而跳过 catch 里面的 next

如果 fn 运行途中有报错,那么 catch 拿到这个 err,会调用回调函数 next 并将 err 作为第一个参数传入。而这个,正好是 Express 处理异常所需要的。

使用

使用的时候就直接把那个有可能有异步异常的异步函数给套起来就行了:

js 复制代码
app.get(
  '/your/api/path',
  asyncHandler(async (req, res, next) => {
    ... // 业务代码
  })
);

引用 References

相关推荐
橙露11 小时前
Webpack/Vite 打包优化:打包体积减半、速度翻倍
前端·webpack·node.js
十五年专注C++开发16 小时前
libuv:一个跨平台的C++异步 I/O 库
开发语言·c++·node.js·libuv·vlibuv
困惑阿三16 小时前
客户消息及时反馈
nginx·node.js·飞书·企业微信
饥饿的帕尼尼18 小时前
Claude Code本地安装使用教程
node.js·github·claude
小民AI实战笔记18 小时前
NVM实战指南:高效管理你的Node.js环境
前端·node.js
gCode Teacher 格码致知21 小时前
Javascript提高:Node.js readline 模块 完整使用教程
javascript·node.js
小p2 天前
nodejs学习6:nodejs应用的优雅退出
node.js
军哥全栈AI2 天前
Windows11 彻底卸载Node.js(无残留,适配所有版本)
npm·node.js
困惑阿三2 天前
全栈部署排雷手册:从 405 报错到飞书推送成功
服务器·前端·后端·nginx·阿里云·node.js·飞书
Andytoms2 天前
Node.js 版本和 pnpm 版本的对应关系
node.js