如何在域错误处理程序中发送响应

时间:2013-03-03 02:03:11

标签: node.js http

我有类似的东西:

var domain = require ("domain");
var http = require ("http");

var d = domain.create ();
d.on ("error", function (error){
    console.error (error);
    //res.writeHead (500)
    //res.end ()
});
d.run (function (){
    http.createServer (function (req, res){
        null.error
    }).listen (1337, "localhost");
});

我的所有服务器都在域内运行。如果在请求期间发生错误,我想向用户发送500错误,但在错误处理程序内我无法访问响应对象。


我的第一次尝试是为每个请求使用显式域名,如文档所示:

var d = domain.create ();
d.on ("error", function (error){
    //res.writeHead (500);
    //res.end ()
    console.error (error);
});
d.run (function (){
    http.createServer (function (req, res){
        var dreq = domain.create ();
        dreq.add (req)
        dreq.add (res)
        dreq.on ("error", function (error){
            res.writeHead (500);
            res.end ()
            console.error (error);
        });
        null.error
    }).listen (1337, "localhost");
});

永远不会调用dreq错误处理程序,因为reqres从不发出,错误发生在执行时,它是一个TypeError。


我的第二次尝试是使用闭包来保存对res对象的引用,例如事件发射器:

var domain = require ("domain");
var http = require ("http");
var events = require ("events");

var emitter = new events.EventEmitter ();

var d = domain.create ();
d.on ("error", function (error){
    emitter.emit ("error", error);
});
d.run (function (){
    http.createServer (function (req, res){
        emitter.once ("error", function (error){
            res.writeHead (500);
            res.end ();
            console.error (error);
        });
        null.error
    }).listen (1337, "localhost");
});

这个工作,错误被捕获在错误处理程序中然后发出,所以我可以使用响应对象向用户发送消息。如果您对node.js基础知识知之甚少,那么您将看到此变通方法已被完全排除错误。如果事件循环上有5个用户请求,其中1个执行抛出错误的任务,则发射器将执行所有错误处理程序,并且当只有1个用户应该收到500个错误时,将通知500个用户500个错误错误。


我的最后一次尝试是为每个请求创建子上下文。文档没有说明这种模式。这对我来说有点混乱:

  

为了防止过多的内存使用,域对象本身不会隐式添加为活动域的子项。如果是这样的话,那么防止请求和响应对象被正确地进行垃圾收集就太容易了。

     

如果要将Domain对象作为父域的子项嵌套,则必须显式添加它们,然后再将其处置掉。

var domain = require ("domain");
var http = require ("http");

var d = domain.create ();
d.on ("error", function (error){
    console.error (error);
});
d.run (function (){
    http.createServer (function (req, res){
        var dreq = domain.create ();
        dreq.on ("error", function (error){
            res.writeHead (500);
            res.end ()
            console.error (error);
            dreq.dispose ();
        });
        dreq.run (function (){
            null.error
            //...
            //dreq.dispose ();
        });
    }).listen (1337, "localhost");
});

我是否介绍了内存泄漏?


简单的解决方案是为每个请求分配一个唯一的ID,并将它们保存在一个对象或数组中,当发射器发出时,找到必须在给定唯一ID的情况下执行的处理程序。完全不可接受。


如果我无法保存对res对象的引用,如何向域错误处理程序内的用户发送错误?

3 个答案:

答案 0 :(得分:1)

此解决方案是赢家:

var domain = require ("domain");
var http = require ("http");

var d = domain.create ();
d.on ("error", function (error){
    console.error (error);
});
d.run (function (){
    http.createServer (function (req, res){
        var dreq = domain.create ();
        dreq.add (req);
        dreq.add (res);
        dreq.on ("error", function (error){
            res.on ("close", function (){
                dreq.exit ();
            });
            res.writeHead (500);
            res.end ()
            console.error (error);
            dreq.exit();
        });
        dreq.run (function (){
            null.error
        });
    }).listen (1337, "localhost");
});

https://github.com/joyent/node/issues/4905

答案 1 :(得分:0)

你上次发布的解决方案实际上是你应该做的。这与文档建议的嵌套类型不同。你正在做的就是在域中包装潜在的(或者,在这种情况下,肯定的)错误代码,这样当它发出由域处理的错误时。

答案 2 :(得分:0)

这个解决方案适用于我:

var http = require('http');
var domain = require('domain');

var server = http.createServer (function (req, res) {
    var reqDomain = domain.create();
    reqDomain.on('error', function (error) {
        res.writeHead(500);
        res.end('error 500');
        console.error(error);
    });
    res.on('close', function () {
        reqDomain.dispose();
    });
    reqDomain.run(function () {
        // Request handler code here
        null.error
    });
}).listen(3000);

server.on('error', function (error) {
    console.error('Server error: ' + error);
});