捕获 async-await 快速路由处理程序中的所有错误

Posted

技术标签:

【中文标题】捕获 async-await 快速路由处理程序中的所有错误【英文标题】:Catching all errors in async-await express route handlers 【发布时间】:2018-10-07 09:47:54 【问题描述】:

假设我有这样的路线:

app.get('/broken', (req, res) => 
  throw new Error('Broken!');
);

这永远不会向客户端发送响应。

但是,我可以为所有错误添加一个中间件:

const errorMiddleware = (error, req, res, next) => 
  if (error) 
    console.error(error);
    return res.status(500)
      .json(
        message: 'Internal server error', 
      );
  
  next(error);
;

但这不适用于async 路由,因为它们不直接throw

例如,这将不起作用:

app.get('/broken', async (req, res) => 
  throw new Error('Broken!');
);

所以我可以像这样创建一个包装器:

const asyncRoute = f => (req, res, next) => 
  return Promise.resolve(f(req, res, next)).catch(next);
;

app.get('/broken', asyncRoute(async (req, res) => 
  throw new Error('Broken!');
));

但这真的很痛苦,因为现在我必须为每条路线调用这个函数!

有什么更好的方法来处理这个问题?


Is there a way to wrap an await/async try/catch block to every function?的答案就是我上面描述的 how to use Promise with express in node.js? 的答案不使用await

【问题讨论】:

你认为路由回调async 有什么好处? Express 不使用承诺,所以......纯粹是为了在其中获得await 语义吗?如果是这样,您的包装器就是这样做的正确方法。 (你可以看看Koa。) 好吧,我的一些路由需要多次 async 调用(例如数据库、API、bcrypt),因此在 async 上下文中更容易编写。 @T.J.Crowder 如果我没有通过承诺(例如123),那么我希望强制承诺(例如Promise.resolve(123))。请注意,Promise.resolve(Promise.resolve(x)) 被展平为Promise.resolve(x) 好的。我没有看到任何理由将非承诺传递给名为asyncRoute 的东西,所以我没有意识到你想要处理这个问题。 :-) 【参考方案1】:

基本上,您不想直接将async 函数传递给 Express 的app.get,因为app.get 不处理函数返回的承诺。所以你需要包装那些async 处理程序(就像你正在做的那样)。

您可以通过在模块顶部给自己一个实用方法来避免每次都这样做:

const appGet = handler => app.get(asyncRoute(handler));

然后用它代替app.get:

appGet('/broken', async (req, res) => 
  throw new Error('Broken!');
);

在某个时候(可能不是现在),您可能想查看Koa。

【讨论】:

以上是关于捕获 async-await 快速路由处理程序中的所有错误的主要内容,如果未能解决你的问题,请参考以下文章

快速错误处理和异步等待

播放框架 1.2.5 的路由查询

iOS异常信号的捕获和简单处理

在 .net 4 上使用 async-await

Springboot捕获全局异常404-NoHandlerFoundException及Swagger/静态路由处理

具有通过护照实例的快速路由中的路由分离