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

我想使用Node.js域来捕获exception。 它到目前为止工作,但有一个地方,我不能让域来赶上例外。 在callback中的exception2被捕获并在domain.on('error')处理程序中处理,但是exception1不被捕获。 奇怪的是,当引发exception1时,它并没有像我期望的那样closures节点。 这是我的示例应用程序:

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,我注释掉exception1。

问题是Connect的路由过程中发生了exception,在执行过程中有一个try/catch块,还有一个默认的error handling程序,在非生产模式下运行时会打印出堆栈跟踪详细信息。 由于exception是在Express内部处理的,因此它永远不会到达您的外层以供域处理。

它与exception2不同之处在于, '/'路由的处理函数直接由Connect块执行,与原来的Express调用相同。 第二个exception发生在callback中 ,在一些I / O操作返回之后,因此由源自Node的事件循环I / O处理程序的堆栈执行,所以Express的try/catch不可用于阻止该exception并保存应用程序服务器。 事实上,如果你注释掉所有的域名,并且运行exception2它会使Node崩溃。

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

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

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

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

@ user1007983

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

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

解决这个问题的另一种方法是从处理程序断开连接,就像将代码包装在setImmediate块中一样

我试过try/catch块(这可能不会像你认为的那样用asynchronous代码工作)。 我用几种不同的方法尝试了节点 。 但是我无法处理在第三方库(sequelize)中抛出的exception。 为什么我得到这个例外? 那是因为生成的SQL格式不正确。 (我的错)。

无论如何,最适合我和我的(小)项目的解决scheme是永远使用。 让exception发生,但如果他们这样做,再次启动节点。 我怀疑这是最优雅的解决scheme,但它适用于我和我的小项目。

在一个更大的项目中,与聚类API相结合的域名可能是一个不错的select。

温斯顿是另一种select。 把forever和winston结合起来可能会很酷,所以如果你有个例外,你可以用winston给你发邮件 ,这样你就可以修改代码。 同时, forever会很高兴地重新启动你的应用程序。

我在testing基于域的error handling时遇到了这个问题。

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