【问题标题】:Unable to handle exception with node.js domains using express无法使用 express 处理 node.js 域的异常
【发布时间】:2012-10-25 02:01:58
【问题描述】:

我想使用 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。

【问题讨论】:

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


    【解决方案1】:

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

    我采用了 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));
    

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        【解决方案3】:

        @user1007983

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

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

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

        【讨论】:

          【解决方案4】:

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

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

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

          【讨论】:

            【解决方案5】:

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

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

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

            【讨论】:

            • 那么根据您的评论,生产中的域处理程序将捕获异常?
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-07-06
            • 2012-12-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-03-04
            相关资源
            最近更新 更多