Express 应用程序中未处理的拒绝
Unhandled rejections in Express applications
我的 express 应用程序中有很多基于 ES6 promise 的代码 运行。如果有一个从未被捕获的错误,我将使用以下代码来处理它:
process.on('unhandledRejection', function(reason, p) {
console.log("Unhandled Rejection:", reason.stack);
process.exit(1);
});
这可以很好地用于调试目的。
但在生产中我想触发 500 错误处理程序,向用户显示标准 "Something went wrong" 页面。我有这个捕获所有当前适用于其他异常的错误处理程序:
app.use(function(error, req, res, next) {
res.status(500);
res.render('500');
});
将 unhandledRejection 放入中间件中不起作用,因为它是异步的并且经常导致 Error: Can't render headers after they are sent to the client.
我将如何在 unhandledRejection
上呈现第 500 页?
假设您正在使用 Express 和一些基于 promise 的代码,如下所示:
readFile()
.then(readAnotherFile)
.then(doSomethingElse)
.then(...)
将 .catch(next)
添加到您的承诺链的末尾,Express 的中间件将使用您的生产错误处理程序成功处理这两个 synchronous/asynchronous 代码。
这是一篇深入了解您正在寻找的内容的精彩文章:https://strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/
Putting the unhandledRejection inside a middleware...often results in 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');
});
Express comes with an in-built error handler, which takes care of any errors that might be encountered in the app. This default error-handling middleware is added at the end of the middleware stack.
If you pass an error to next() and you do not handle it in an error handler, it will be handled by the built-in error handler - the error will be written to the client with the stack trace. The stack trace is not included in the production environment.
Set the environment variable NODE_ENV to “production”, to run the app in production mode.
如果您在开始编写响应后调用 next() 时出现错误,例如,如果您在将响应流式传输到客户端时遇到错误,Express 的默认错误处理程序将关闭连接并发出请求视为失败。
因此,当您添加自定义错误处理程序时,当 headers 已发送到客户端时,您需要委托给 express 中的默认错误处理机制。
我正在使用 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);
});
});
但这太重了:
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。
express-promise-router正是为了解决这个问题而制作的。它允许你路由到 return promises,如果这样的 promise 被错误拒绝,它会调用 next(err)
。
默认情况下,如果您的请求是 async
抛出错误的函数,express 不会将错误传递给中间件。
相反 process.on('unhandledRejection', callback)
被调用,请求将被阻止。
创建库 express-async-errors 来解决这些错误。
您需要将 require('express-async-errors');
添加到您的代码中,库将确保您的所有函数都进入处理程序。
即使是未经处理的拒绝。
我一直在寻找一种干净的方式来处理它,Express 5 现在通过设计来处理异步承诺:
Starting with Express 5, route handlers and middleware that return a
Promise will call next(value) automatically when they reject or throw
an error. For example
我的 express 应用程序中有很多基于 ES6 promise 的代码 运行。如果有一个从未被捕获的错误,我将使用以下代码来处理它:
process.on('unhandledRejection', function(reason, p) {
console.log("Unhandled Rejection:", reason.stack);
process.exit(1);
});
这可以很好地用于调试目的。
但在生产中我想触发 500 错误处理程序,向用户显示标准 "Something went wrong" 页面。我有这个捕获所有当前适用于其他异常的错误处理程序:
app.use(function(error, req, res, next) {
res.status(500);
res.render('500');
});
将 unhandledRejection 放入中间件中不起作用,因为它是异步的并且经常导致 Error: Can't render headers after they are sent to the client.
我将如何在 unhandledRejection
上呈现第 500 页?
假设您正在使用 Express 和一些基于 promise 的代码,如下所示:
readFile()
.then(readAnotherFile)
.then(doSomethingElse)
.then(...)
将 .catch(next)
添加到您的承诺链的末尾,Express 的中间件将使用您的生产错误处理程序成功处理这两个 synchronous/asynchronous 代码。
这是一篇深入了解您正在寻找的内容的精彩文章:https://strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/
Putting the unhandledRejection inside a middleware...often results in 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');
});
Express comes with an in-built error handler, which takes care of any errors that might be encountered in the app. This default error-handling middleware is added at the end of the middleware stack.
If you pass an error to next() and you do not handle it in an error handler, it will be handled by the built-in error handler - the error will be written to the client with the stack trace. The stack trace is not included in the production environment.
Set the environment variable NODE_ENV to “production”, to run the app in production mode.
如果您在开始编写响应后调用 next() 时出现错误,例如,如果您在将响应流式传输到客户端时遇到错误,Express 的默认错误处理程序将关闭连接并发出请求视为失败。
因此,当您添加自定义错误处理程序时,当 headers 已发送到客户端时,您需要委托给 express 中的默认错误处理机制。
我正在使用 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);
});
});
但这太重了:
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。
express-promise-router正是为了解决这个问题而制作的。它允许你路由到 return promises,如果这样的 promise 被错误拒绝,它会调用 next(err)
。
默认情况下,如果您的请求是 async
抛出错误的函数,express 不会将错误传递给中间件。
相反 process.on('unhandledRejection', callback)
被调用,请求将被阻止。
创建库 express-async-errors 来解决这些错误。
您需要将 require('express-async-errors');
添加到您的代码中,库将确保您的所有函数都进入处理程序。
即使是未经处理的拒绝。
我一直在寻找一种干净的方式来处理它,Express 5 现在通过设计来处理异步承诺:
Starting with Express 5, route handlers and middleware that return a Promise will call next(value) automatically when they reject or throw an error. For example