无法使用express处理node.js域的异常

时间:2012-11-05 08:48:38

标签: node.js express exception dns node.js-domains

我想使用Node.js域来捕获异常。它到目前为止工作,但有一个地方我无法获得域来捕获异常。回调中的exception2在domain.on(' error')处理程序中被捕获和处理,但不捕获exception1。奇怪的是,当抛出exception1时,它并没有像我期望的那样关闭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');
      }
    });
});

要执行exception2,我会注释掉异常1。

5 个答案:

答案 0 :(得分:18)

问题是异常发生在Connect's routing期间,它同时具有try/catcharound its execution,以及一个默认错误处理程序,它在运行时打印出堆栈跟踪详细信息非生产模式。由于异常是在Express内部处理的,因此它永远不会到达外层以供域处理。

它与exception2的不同之处在于'/'路由的处理函数由Connect块直接执行,与通过Express的原始调用在同一堆栈中。第二个异常发生在回调中,在一些I / O操作返回后,因此由来自Node的事件循环I / O处理程序的堆栈执行,因此try/catch为Express无法阻止该异常并保存应用服务器。实际上,如果您注释掉所有域名内容,并且exception2行,则会崩溃Node。

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

答案 1 :(得分:4)

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

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

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

答案 2 :(得分:4)

@ user1007983

不,在生产中,尝试/捕获处理仍然存在于Connect / Express中。解决它的方法是在" root"中添加你自己的try / catch块。您可以使用它来发出"错误"连接之前发送到域的事件发送错误响应。

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

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

答案 3 :(得分:0)

我尝试了try/catch个阻止(这可能与您使用异步代码的方式不同)。我已经尝试过几种不同的节点。但我无法处理第三方库(sequelize)中抛出的异常。为什么我得到例外?好吧,这是因为生成的SQL格式不正确。 (我的错)。

Anywho,对我和我的(小)项目最有效的解决方案是使用 forever 。让例外发生,但如果他们这样做,则再次启动节点。我怀疑它是最优雅的解决方案,但它适用于我和我的小项目。

对于较大的项目,域名与 clustering API 相结合可能是一个不错的选择。

Winston 是另一种选择。将forever与winston结合起来可能会很酷,这样如果你得到异常,你就可以拥有winston email you,这样你就可以修复代码了。同时,forever会很乐意为您重新启动应用。

答案 4 :(得分: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));