Express应用程序中未处理的拒绝

Dan*_*iel 51 node.js express es6-promise

我在Express应用程序中运行了很多基于ES6 promise的代码.如果有一个从未被捕获的错误,我正在使用以下代码来处理它:

process.on('unhandledRejection', function(reason, p) {
  console.log("Unhandled Rejection:", reason.stack);
  process.exit(1);
});
Run Code Online (Sandbox Code Playgroud)

这适用于调试目的.

但是在生产中我想触发500错误处理程序,向用户显示标准的"出错了"页面.我有这个捕获当前适用于其他异常的所有错误处理程序:

app.use(function(error, req, res, next) {
  res.status(500);
  res.render('500');
});
Run Code Online (Sandbox Code Playgroud)

将unhandledRejection放在中间件中不起作用,因为它的异步和offen导致a Error: Can't render headers after they are sent to the client.

我将如何渲染500页unhandledRejection

Jar*_*tra 27

将unhandledRejection放在中间件中...通常会导致a Error: Can't render headers after they are sent to the client.

对您的错误处理程序稍作更改:

// production error handler
const HTTP_SERVER_ERROR = 500;
app.use(function(err, req, res, next) {
  if (res.headersSent) {
    return next(err);
  }

  return res.status(err.status || HTTP_SERVER_ERROR).render('500');
});
Run Code Online (Sandbox Code Playgroud)

ExpressJS文档:

Express附带了一个内置的错误处理程序,它可以处理应用程序中可能遇到的任何错误.此缺省错误处理中间件添加在中间件堆栈的末尾.

如果将错误传递给next()并且您没有在错误处理程序中处理它,它将由内置错误处理程序处理 - 错误将通过堆栈跟踪写入客户端.堆栈跟踪不包含在生产环境中.

将环境变量NODE_ENV设置为"production",以在生产模式下运行应用程序.

如果在开始编写响应后调用next()并出现错误,例如,如果在将响应流式传输到客户端时遇到错误,则Express的默认错误处理程序将关闭连接并使请求被视为失败.

因此,当您添加自定义错误处理程序时,您将希望在已将标头发送到客户端时委派给express中的默认错误处理机制.

  • 你好。请添加更多代码。我不知道如何在 Express 应用程序中使用此代码 `process.on('unhandledRejection', error => { /* 我应该在这里做什么 */ });` 来处理 unhandledRejection (2认同)

小智 21

我使用next参数作为catch回调(aka errback)来转发任何未处理的拒绝来表达错误处理程序:

app.get('/foo', function (req, res, next) {
  somePromise
    .then(function (result) {
      res.send(result);
    })
    .catch(next); // <----- NOTICE!
}
Run Code Online (Sandbox Code Playgroud)

或更短的形式:

app.get('/foo', function (req, res, next) {
  somePromise
    .then(function (result) {
       res.send(result); 
    }, next); // <----- NOTICE!
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以err在快速错误处理程序中使用参数发出有意义的错误响应

例如,

app.use(function (err, req, res, /*unused*/ next) {
  // bookshelf.js model not found error
  if (err.name === 'CustomError' && err.message === 'EmptyResponse') {
    return res.status(404).send('Not Found');
  }
  // ... more error cases...
  return res.status(500).send('Unknown Error');
});
Run Code Online (Sandbox Code Playgroud)

恕我直言,全球unhandledRejection事件不是最终的答案.

例如,这容易发生内存泄漏:

app.use(function (req, res, next) {
  process.on('unhandledRejection', function(reason, p) {
    console.log("Unhandled Rejection:", reason.stack);
    res.status(500).send('Unknown Error');
    //or next(reason);
  });
});
Run Code Online (Sandbox Code Playgroud)

但这TOO重:

app.use(function (req, res, next) {
  var l = process.once('unhandledRejection', function(reason, p) {
    console.log("Unhandled Rejection:", reason.stack);
    res.status(500).send('Unknown Error');
    //next(reason);
  });
  next();
  process.removeEventLister('unhandledRejection', l);
});
Run Code Online (Sandbox Code Playgroud)

恕我直言,expressjs需要更好的支持Promise.

  • 所以我们应该总是使用`next`来处理错误,并且没有用于承诺拒绝的全局错误处理程序:(这太糟糕了! (2认同)
  • @iolo 你提到“太重”,你能解释一下吗? (2认同)

Tho*_*mas 12

我认为express-promise-router是为了解决这个问题.它允许您的路由返回承诺,并且next(err)如果这样的承诺被拒绝并且出错,则会调用它.


Seb*_*rin 6

我一直在寻找一种干净的方法来处理它,Express 5 现在通过设计处理异步承诺:

从 Express 5 开始,返回 Promise 的路由处理程序和中间件将在拒绝或抛出错误时自动调用 next(value)。例如

https://expressjs.com/en/guide/error-handling.html


Dav*_*erg 5

默认情况下,如果您的请求是async抛出错误的函数,express 不会将错误传递给中间件。相反process.on('unhandledRejection', callback)被调用,请求将被阻塞。

创建库express-async-errors来解决这些错误。

您需要添加require('express-async-errors');到您的代码中,库将确保您的所有函数都进入处理程序。即使这是一个未经处理的拒绝。