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

我有很多基于ES6承诺的代码在我的快车应用程序中运行。 如果有一个从未被捕获的错误,我使用下面的代码来处理它:

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

这适用于debugging目的。

但在生产中,我想触发500error handling程序,向用户显示标准的“出错”页面。 我有这个捕获所有error handling程序,目前适用于其他例外:

 app.use(function(error, req, res, next) { res.status(500); res.render('500'); }); 

将未处理的拒绝放在中间件内不起作用,因为它是asynchronous的,并导致Error: Can't render headers after they are sent to the client.

我将如何去unhandledRejection一个unhandledRejection拒绝500页?

把unhandledRejection放在一个中间件内…经常会导致一个Error: Can't render headers after they are sent to the client.

稍微改变你的error handling程序:

 // 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'); }); 

从ExpressJS文档 :

Express附带了一个内置的error handling程序,该程序负责处理应用程序中可能遇到的任何错误。 这个默认的error handling中间件被添加到中间件堆栈的末尾。

如果你将一个错误传递给next()而你没有在error handling程序中处理它,它将由内置error handling程序处理 – 错误将被写入到具有堆栈跟踪的客户端。 堆栈跟踪不包括在生产环境中。

将环境variablesNODE_ENV设置为“生产”,以生产模式运行应用程序。

如果您在开始编写响应之后调用next(),例如,如果在将响应传输到客户端时遇到错误,则Express的默认error handling程序将closures连接,并使请求被视为失败。

所以,当你添加一个自定义的error handling程序时,你将需要以express的方式委托给默认的error handling机制,这时头文件已经被发送到客户端。

我使用next参数作为catchcallback(又名errback)转发任何未处理的拒绝来表示error handling程序:

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

或更短的forms:

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

然后我们可以在error handling函数中用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需要更好的支持承诺。

假设您正在使用Express和一些基于承诺的代码,如下所示:

readFile() .then(readAnotherFile) .then(doSomethingElse) .then(...)

.catch(next)添加到承诺链的末尾,Express的中间件将成功处理使用您的生产error handling程序的同步/asynchronous代码。

以下是一篇很好的文章,深入了解您所寻找的内容: https : //strongloop.com/strongblog/async-error-handling-expressjs-es7-promises-generators/

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