问题描述
到目前为止,我已经检查过以通用方式处理 promise 的错误,unhandledRejection 事件处理程序是最好的方法。就像下面一样:
process.on('unhandledRejection',(reason,promise) => {
console.log('error: unhandledRejection');
});
现在,当我想访问此事件处理程序中的请求和响应对象时,挑战就来了。这样我就可以以通用方式生成 500 响应,因此我不需要在项目中的任何地方添加 promise 异常处理。
有人建议我使用:
app.use(function (req,res,next) {
process.on('unhandledRejection',function (reason,promise) {
console.error("Here I can access request objects.")
// Unregister unhandledRejection
});
});
但在上述情况下,事件侦听器将被多次注册,并且只有在发生异常时才会取消注册。由于事件会被多次注册,所以代码(console.error("Here I can access request objects.")
)会被多次触发。
有什么建议吗?如果我可以在 app.use 之外访问请求和响应对象?
提前致谢!
解决方法
默认 express 会处理错误。通过快递文件:
Express 带有一个嵌入式错误处理程序,它将处理应用程序中可能发生的任何错误。这个默认的错误处理中间件函数添加在中间件函数栈的末尾。
next() 如果你给函数一个错误并且没有在自定义错误处理程序中处理它,这个错误由嵌入的错误处理程序处理;错误通过堆栈跟踪打印在客户端上。生产环境中不包含堆栈跟踪。
将环境变量的 NODE_ENV 值设置为 production 以在生产模式下运行应用程序。
当打印错误时,会在响应中添加以下信息:
-
res.statusCode err.status 字段的值来自该字段 (或 err.statusCode)。如果此值不在 4xx 或 5xx 范围内, 它将设置为 500。
-
res.statusMessage 字段根据 状态码。
-
如果在生产模式下,正文(body)变成了 状态码消息,否则为 err.stack。
-
err.headers 对象中指定的任何标头。
next() 如果在开始写入响应后调用函数时出错(例如,如果在将响应传输到客户端时遇到错误),默认的 Express 错误处理程序将关闭连接并使请求失败.
当您添加自定义错误处理程序时,如果标头已经发送到客户端,您应该授权默认的 Express 错误处理程序:
function errorHandler (err,req,res,next) {
if (res.headersSent) {
return next(err)
}
res.status(500)
res.render('error',{ error: err })
}
在代码中有错误的情况下多次调用 next() 函数可能会触发默认错误处理程序,即使自定义错误处理程序中间件已就位。
这很容易导致内存泄漏:
app.use(function (req,next) {
process.on('unhandledRejection',功能(原因,承诺){
console.error("在这里我可以访问请求对象。")
// 取消注册 unhandledRejection
});
});
此外,您无法访问 'unhandledRejection' 中的响应对象,如果 express 可以处理该对象以向用户发送 '500' 状态代码,那么您为什么要访问该对象。无论何时何地需要,捕捉承诺总是一个好习惯。但是,如果仍然没有涵盖某些承诺,那么也有一些库可以处理它,例如:express-promise-router,express-async-errors
我们可以在 express 错误处理程序中使用 err 参数发出有意义的错误响应,并将响应发送给用户。例如,
app.use((err,next) => {
if (err.name === 'CustomError' && err.message === 'EmptyResponse') {
return res.status(404).send('Not Found');
}
// ... more error cases...
return res.status(500).send('Internal Server Error');
});