我在Express应用程序中运行了很多基于ES6 promise的代码。如果有错误从未被捕获,我可以使用以下代码来处理它:
process.on('unhandledRejection', function(reason, p) {
console.log("Unhandled Rejection:", reason.stack);
process.exit(1);
});
这适用于调试目的。
在生产中,我想触发500错误处理程序,向用户显示标准"出错了"页。我有这个捕获当前适用于其他异常的所有错误处理程序:
app.use(function(error, req, res, next) {
res.status(500);
res.render('500');
});
将unhandledRejection放在中间件中不起作用,因为它的异步和offen导致Error: Can't render headers after they are sent to the client.
如何在unhandledRejection
上呈现500页?
答案 0 :(得分:24)
将unhandledRejection放在中间件中...通常会产生
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');
});
Express附带内置错误处理程序,可处理应用程序中可能遇到的任何错误。此缺省错误处理中间件将添加到中间件堆栈的末尾。
如果将错误传递给next()并且您没有在错误处理程序中处理它,则它将由内置错误处理程序处理 - 错误将通过堆栈跟踪写入客户端。堆栈跟踪不包含在生产环境中。
将环境变量NODE_ENV设置为“production”,以便在生产模式下运行应用程序。
如果在开始编写响应后调用next()并出现错误,例如,如果在将响应流式传输到客户端时遇到错误,则Express的默认错误处理程序将关闭连接并考虑请求失败。
因此,当您添加自定义错误处理程序时,您将希望在已将标题发送到客户端时委派给express中的默认错误处理机制。
答案 1 :(得分:19)
我使用next
参数作为catch
回调(又名errback)
转发任何未处理的拒绝来表达错误处理程序:
app.get('/foo', function (req, res, next) {
somePromise
.then(function (result) {
res.send(result);
})
.catch(next); // <----- NOTICE!
}
或更短的形式:
app.get('/foo', function (req, res, next) {
somePromise
.then(function (result) {
res.send(result);
}, next); // <----- NOTICE!
}
然后我们可以发出有意义的错误响应
在快速错误处理程序中使用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');
});
恕我直言,全球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);
});
});
但 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);
});
恕我直言,expressjs需要更好的支持Promise。
答案 2 :(得分:11)
express-promise-router是为了解决这个问题。它允许您的路由返回承诺,并且如果此类承诺被拒绝且错误,则会调用next(err)
。
答案 3 :(得分:3)
假设您正在使用Express和一些基于承诺的代码,如下所示:
readFile()
.then(readAnotherFile)
.then(doSomethingElse)
.then(...)
在您的保证链的末尾添加.catch(next)
,Express的中间件将使用您的生产错误处理程序成功处理同步/异步代码。
这是一篇很棒的文章,深入探讨了您的目标:https://strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/
答案 4 :(得分:2)
默认情况下,如果您的请求是引发错误的async
函数,则express不会将错误传递给中间件。
而是调用process.on('unhandledRejection', callback)
,请求将被阻止。
创建了express-async-errors库来解决这些错误。
您需要将require('express-async-errors');
添加到代码中,该库将确保所有函数都到达处理程序。
即使是未处理的拒绝。
答案 5 :(得分:0)
我一直在寻找一种干净的方式来处理它,Express 5 现在通过设计处理异步承诺:
<块引用>从 Express 5 开始,路由处理程序和中间件返回一个 Promise 在拒绝或抛出时会自动调用 next(value) 一个错误。例如