4

我有类似的东西:

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错误处理程序永远不会被调用,因为并且req永远res不会发出,错误发生在执行时,它是一个 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 时,5 个用户将收到 500 错误通知错误。


我最后一次尝试是为每个请求创建子上下文。文档对这种模式只字未提。这让我有点困惑:

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

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

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对象的引用,如何在域错误处理程序中向用户发送错误?

4

3 回答 3

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

于 2013-03-04T10:21:41.313 回答
0

你最后发布的解决方案实际上是你应该做的。这与文档建议反对的嵌套类型不同。您所做的只是将潜在的(或者,在这种情况下,肯定是)错误代码包装在域中,以便在发生错误时由域处理。

于 2013-03-03T07:41:14.323 回答
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);
});
于 2013-03-03T07:48:34.983 回答