我想使用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。
答案 0 :(得分:18)
问题是异常发生在Connect's routing期间,它同时具有try/catch
块around 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));