15

我想使用 Node.js 域来捕获异常。到目前为止它正在工作,但是有一个地方我无法让域来捕获异常。回调中的 exception2 在 domain.on('error') 处理程序中被捕获和处理,但 exception1 没有被捕获。奇怪的是,当异常 1 被抛出时,它并没有像我期望的那样关闭 Node。这是我的示例应用程序:

var domain = require('domain');
var request = require('request');
var express = require('express');

var serverDomain = domain.create();
serverDomain.on('error', function(err) {
  console.log("Server Domain Error: " + err);
});

var app;

serverDomain.run(function() {
  app = express();
  app.listen(3000);
});

app.use(function(req, res, next) {

  var reqDomain = domain.create();
  reqDomain.add(req);
  reqDomain.add(res);
  reqDomain.on('error', function(err) {
    console.log("Req Domain Error: " + err);
    reqDomain.dispose();
    next(err);
  });

  next();
});

app.get('/', function(req, res) {
  var uri = "http://google.com";

  exception1.go();

  request.get({url:uri, json: {}},
    function (error, response, body) {
      if(response.statusCode === 200) {
        exception2.go();
        res.send('Success getting google response');
      }
    });
});

为了让异常 2 执行,我注释掉异常 1。

4

5 回答 5

18

问题是异常发生在Connect 的路由期间,它有一个围绕其执行try/catch的块,以及一个默认的错误处理程序,当在非生产模式下运行时打印出堆栈跟踪详细信息。由于异常是在 Express 内部处理的,因此它永远不会到达您的外层以供域处理。

它的不同之处在于路由exception2的处理函数'/'直接由该 Connect 块执行,与通过 Express 的原始调用在同一个堆栈中。第二个异常发生在回调中,在某些 I/O 操作返回之后,因此由源自 Node 的事件循环 I/O 处理程序的堆栈执行,因此try/catchExpress 无法捕获该异常并保存应用服务器。事实上,如果你注释掉所有领域的东西,并且绊倒exception2它会使 Node.js 崩溃。

由于只有未处理的异常被路由到域机制,并且由于在其上方的调用堆栈中exception1有一个try/catch可见的,所以异常被处理,而不是转发到域。

于 2012-11-05T20:57:54.823 回答
4

Connect-domain 允许您捕获连接模块的所有错误,包括 express。

连接域 https://github.com/baryshev/connect-domain

express3 的示例:http: //masashi-k.blogspot.com/2012/12/express3-global-error-handling-domain.html

于 2012-12-21T00:05:43.290 回答
4

@user1007983

不,在生产中,Connect/Express 中仍然存在 try/catch 处理。解决它的方法是在“根”中添加您自己的 try/catch 块,然后您可以使用它在连接发送错误响应之前向域发出“错误”事件。

try {
    // .. code here ..
} catch (err) {
    domain.emit('error', err);
}

绕过它的另一种方法是与处理程序断开连接,例如将代码包装在 setImmediate 块中

于 2013-06-19T10:10:11.203 回答
0

我已经尝试过try/catch块(这可能与您对异步代码的想法不同)。我以几种不同的方式尝试了节点。但是我无法处理在 3rd 方库(续集)中引发的异常。为什么我得到了异常?嗯,这是因为生成的 SQL 格式不正确。(我的错)。

Anywho,对我和我的(小)项目最有效的解决方案是永远使用。让异常发生,但如果发生,请再次启动节点。我怀疑这是最优雅的解决方案,但它适用于我和我的小项目。

对于较大的项目,结合集群 API的域可能是一个不错的选择。

温斯顿是另一个选择。与 winston结合可能会很酷,forever这样如果您确实遇到异常,您可以让winston 给您发送电子邮件,这样您就可以修复代码。同时,forever很乐意为您重新启动应用程序。

于 2013-10-02T15:52:02.677 回答
0

我在测试基于域的错误处理时遇到了这个问题。

我采用了 Issac 在此处建议的方法,并进行了一些小的更改:使用“domain.active”获取当前活动的域并在其上发出错误事件,并且我使用了一个包装函数来避免修改所有我的处理函数:

domainWrapper = function(func) {
    return function(req, res) {
        try {
            return func(req, res);
        } catch (err) {
            domain.active.emit('error', err);
        }
    }
}

然后改变了这种事情:

app.get('/jobs', handlerFunc);

对此:

app.get('/jobs', domainWrapper(handlerFunc));
于 2014-02-14T14:24:39.513 回答