在 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 抛出的错误,CastErrorCast 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 的最佳实践是啥?

Express 和 node.js 中的 HTML?

在 JWT 中存储秘密信息,使用 Node.js - Express 后端

在 Node.js/Express 中记录所有请求

如何让 twitter 引导模式在 node js express js 中工作?