在 Node.js + Express 中使用 Promise 处理错误
Posted
技术标签:
【中文标题】在 Node.js + Express 中使用 Promise 处理错误【英文标题】:Error handling in Node.js + Express using promises 【发布时间】:2014-12-15 17:22:16 【问题描述】:使用 Node.js + Express (4) + Mongoose(使用 Promise 而不是回调),我无法理清如何整理我的错误处理。
我得到的(相当简化的)是:
app.get('/xxx/:id', function(request, response)
Xxx.findById(request.params.id).exec()
.then(function(xxx)
if (xxx == null) throw Error('Xxx '+request.params.id+' not found');
response.send('Found xxx '+request.params.id);
)
.then(null, function(error) // promise rejected
switch (error.name)
case 'Error':
response.status(404).send(error.message); // xxx not found
break;
case 'CastError':
response.status(404).send('Invalid id '+request.params.id);
break;
default:
response.status(500).send(error.message);
break;
);
);
在这里,在“承诺被拒绝”部分的开关中,Error
是我为未找到的潜在有效 id 抛出的错误,CastError
是 Cast to ObjectId failed em> 由 Mongoose 抛出一个无效的 id,并且 500 错误可以通过将 throw Error()
错误输入为 throw Err()
来触发(导致 ReferenceError: Err is not defined)。
但是像这样,我的每条路线都有这个笨拙的大开关来处理不同的错误。
如何集中处理错误?开关能否以某种方式隐藏在某些中间件中?
(我确实希望我可以在 'promise denied' 块中使用 throw error;
重新抛出,但我无法让它工作)。
【问题讨论】:
你不能让那个错误处理函数全局化(到处都一样吗?),然后在每条路由中将它传递给.then(null, …)
?
@Bergi:谢谢——我想知道一个全局错误处理函数,我只是觉得应该有一种更“原生”的做事方式。全局错误处理函数工作正常——如果你把它作为答案,我会接受的!
@ChrisV 你所说的更“原生”的方式是使用基于承诺的路由器,而不是默认的路由器,它会让你return Xxx.findById(...
然后检查拒绝。我认为 spion 在某个时候写过一篇。
【参考方案1】:
我会创建中间件来处理错误。使用next()
404s。和next(err)
其他错误。
app.get('/xxx/:id', function(req, res, next)
Xxx.findById(req.params.id).exec()
.then(function(xxx)
if (xxx == null) return next(); // Not found
return res.send('Found xxx '+request.params.id);
)
.then(null, function(err)
return next(err);
);
);
404 处理程序
app.use(function(req, res)
return res.send('404');
);
错误处理程序
app.use(function(err, req, res)
switch (err.name)
case 'CastError':
res.status(400); // Bad Request
return res.send('400');
default:
res.status(500); // Internal server error
return res.send('500');
);
您可以通过发送如下 json 响应来进一步改进:
return res.json(
status: 'OK',
result: someResult
);
或
return res.json(
status: 'error',
message: err
);
【讨论】:
当我按照您的建议添加return next(err);
时,它会到达该语句,然后就坐在那里,并带有“等待本地主机...”。如果您确信该方法应该有效,那么也许我的代码中还有其他问题,但我一辈子都看不到是什么!
你有没有在那之后处理404
的路线,你是否使用app.get('/xxx/:id', function(req, res, next)
。
如何处理可能引入泄漏引用的不可预测的编程错误(如 ReferenceError)。在这种情况下,官方文档建议重启进程,但是你实现的这个中间只会让节点保持活动状态。
@bpcee 好点,中间件应该做更多的事情,只捕获预期可能发生的错误并抛出其余的错误。
遗憾的是,如果您只是在中间件中抛出错误,节点进程不会崩溃,因为 express 将每个函数 (req, res, next) 包装在 try/catch 中。仍在努力找出一个优雅的解决方案...如果您有任何问题,请告诉我。以上是关于在 Node.js + Express 中使用 Promise 处理错误的主要内容,如果未能解决你的问题,请参考以下文章
在 Node.js + Express 中使用 Promise 处理错误
使用 express.js 在 node.js 中提供 html 的最佳实践是啥?