2013-03-03 61 views
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錯誤處理程序不會被調用,因爲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個請求發出錯誤,則發射器將執行所有錯誤處理程序,並且只有其中一個應收到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對象的引用,我怎麼能發送錯誤域錯誤處理程序中的用戶?

+0

加上'DREQ = NULL;'dreq.dispose後'(); '?! – xrDDDD 2013-07-05 17:28:28

回答

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

0

你上次發佈解決方案實際上是你應該做的。這與文檔建議的嵌套類型不同。你所做的只是將潛在的(或者,在這種情況下,肯定是)錯誤的代碼包裝在域中,以便當它發生錯誤時被域處理。

+0

但是,如果有1kk的併發用戶,則數組/對象將具有1kk的屬性,因爲它們中的每一個都會有一個id。 – 2013-03-03 10:11:04

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); 
}); 
+0

我還需要捕獲服務器初始化期間的錯誤('listen()'函數之前的代碼) – 2013-03-03 10:13:05

+0

您可以使用'error'事件捕獲服務器錯誤。我在回答中更新代碼。 – 2013-03-03 10:30:43

+0

我的意思是在使用'createServer()'創建服務器之前的錯誤,例如,在'require(「domain」)'之後寫入'null.error'。我做了一些異步任務,然後開始監聽套接字。我需要在初始化期間捕獲這些錯誤。 – 2013-03-03 11:05:22