在快递中处理异常

我无法理解如何处理它看起来像是express的一个非常基本的方面。 如果我有一些在异步回调中引发异常的代码,我无法捕获该异常,因为在回调运行时try / catch块不在范围内。 在这些情况下,浏览器将挂起,直到它最终放弃说明服务器没有响应。 这是一个非常糟糕的用户体验。 我宁愿能够立即向客户返回500错误。 默认的快速错误处理程序显然不处理这种情况。 以下是一些示例代码:

var express = require("express");

var app = express();
app.use(app.router);
//express error handler (never called)
app.use(function(err, req, res, next) {
    console.log(err);
    res.send(500);
});

app.get("/test", function(req, res, next) {
    require("fs").readFile("/some/file", function(err, data) {
        a.b(); //blow up
    });
});

app.listen(8888);

在上面的代码中,ab()行会引发“ReferenceError:a未定义”异常。 定义的错误处理程序从不被调用。 请注意,在这种情况下,由fs.readFile()返回的err对象为空,因为文件已被正确读取。 该错误是异步处理程序中的代码。

我已经阅读了关于使用节点的uncaughtExpception这篇文章,但文档说不使用该方法。 即使我使用它,我又会如何将500响应发送回用户? 快速响应对象不再供我使用。

那么你如何处理这种情况呢?


好吧,我只是想发布一个完全不同的答案,因为我的第一个答案有一些有价值的信息,但事后看来是脱离主题的。

简短的回答 :正确的事情是已经发生的事情:你的程序应该打印一个堆栈跟踪并退出并报错。

潜在的思想

所以我认为你需要考虑不同类别的错误。 我的第一个回答涉及数据相关的错误,一个写得很好的程序可以并且应该干净地处理。 你所描述的是一个CRASH。 如果您阅读了链接到的node.js文档,则这是正确的。 您的程序在这一点上唯一有用的功能是通过堆栈跟踪退出,并允许进程管理员重新启动并获得理解状态。 一旦程序崩溃,由于极其广泛的错误可能是异常进入堆栈顶部的根本原因,它本质上是不可恢复的。 在您的具体示例中,每次都会继续发生此错误,直到修复源代码错误并重新部署应用程序。 如果您担心未经测试的错误代码将进入您的应用程序,那么添加更多未经测试的错误处理代码并不能真正解决正确的问题。

但简而言之,不,没有办法获得引发此异常的HTTP请求对象的引用,所以AFAIK不能改变浏览器中最终用户所感知的方式,除了在中间反向代理层处理此外您可以在其中配置粗略的超时并发送更友好的错误页面(对于任何不适用于完整HTML文档的请求,这当然毫无用处)。

节点中错误处理的圣经

在我看来,Dave Pacheco在Node.js中的错误处理是关于此主题的权威性工作。 它是全面的,广泛的,彻底的。 我建议定期阅读和重新阅读。


要解决@ asparagino的评论,如果未处理的异常很容易重现或发生频率高,这不是一个边缘情况,这是一个错误。 正确的做法是改善您的代码,以防止在这种情况下生成未捕获的异常。 实际上处理条件,从而将程序员错误转换为操作错误,并且程序可以在没有重新启动且没有未捕获异常的情况下继续。


你应该通过app.use(error, req, res, next)使用express的错误处理中间件app.use(error, req, res, next) 。 Express会维护一个单独的中间件堆栈,当正常的中间件堆栈抛出未捕获的异常时,它会使用它。 (注意,表达式只是查看回调的参数(期望参数的数量),将其归类为常规中间件或错误处理中间件,这有点神奇,所以请记住,您必须声明上述参数以便快速理解这是一个错误处理中间件)。

根据你的问题和意见,只要明白在node.js中异常并不是那么有用,因为每个异步调用都会得到一个新的堆栈,这就是为什么回调在任何地方都被使用,并且第一个参数是普遍错误的原因。 例子中的try/catch块只会捕获由findById直接抛出的异常(就像if id未定义,因为它在你的代码片段中),但是一旦实际调用数据库,就是这样,调用堆栈结束并且在节点调用异步IO回调时完全不同的调用堆栈开始之前不会再发生异常。

感谢您的答案,但这只适用于如果我把try / catch放在异步回调中并让catch执行next(exp)。 我想避免在每个异步回调中分开try / catch块。

不,这不是事实。 你不必手动呼叫next(exp) 。 Express会捕获错误并为您触发错误处理中间件(无论如何,它都是开发人员友好的异常报告页面)。 即使在“正常”错误条件下,异步库也不会抛出异常。 他们将错误传递给回调函数,所以一般情况下,您不必为节点中的try / catch而烦恼。 永远不要忽略传递给回调函数的错误参数,并且你没事。

您不会在节点中看到此样板文件:

someDb.query(someCriteria, function (error, result) {
  try {
    //some code to deal with result
  } catch (exception) {
    callback(exception);
  }
});

你确实看到这个:

someDb.query(someCriteria, function (error, result) {
  if (error) {
    callback(error);
    return;
  }
  //some code to deal with result
});

节点处理IO的方式不同,这意味着调用堆栈的工作方式不同,这意味着异常工作方式不同,这意味着错误处理工作方式不同 您可以编写一个稳定的节点/快速应用程序,在不编写任何try / catch的情况下处理错误而不会崩溃。 (express有一个处理未被捕获的错误,一直到最顶层)。 这不是一个功能限制,它只是异步IO的一个顺序,意味着你必须以不同的方式编写代码,并用回调而不是异常来处理错误。 把它看作是一种“限制”,而不是“它的方式”,是对真正只是技术现实的东西提出了否定的含义。 在同步和异步范例中都有干净而强大的异常处理模式。

链接地址: http://www.djcxy.com/p/46459.html

上一篇: Handling exceptions in express

下一篇: node.js error when an http.request is issued to a server that is not responding