Ion*_*zău 5 javascript http node.js
我有一个非常基本的http服务器:
require("http").createServer(function (req, res) {
res.end("Hello world!");
}).listen(8080);
Run Code Online (Sandbox Code Playgroud)
如何监听服务器崩溃,以便我可以发送500状态代码作为响应?
process.on("uncaughtException", handler)在process级别上听作品,但我没有请求和响应对象.
我看到的一个可能的解决方案是try - catch在createServer回调中使用语句,但我在寻找是否有更好的解决方案.
我试着error在server对象上侦听事件,但没有任何反应:
var s = require("http").createServer(function (req, res) {
undefined.foo; // test crash
res.end("Hello world!");
});
s.on("error", function () { console.log(arguments); });
s.listen(8080);
Run Code Online (Sandbox Code Playgroud)
您可以使用节点的内置域模块.
域提供了一种将多个不同IO操作作为单个组处理的方法.如果注册到域的任何事件发射器或回调发出错误事件或抛出错误,那么将通知域对象,而不是丢失process.on('uncaughtException')处理程序中的错误上下文,或导致程序立即退出并显示错误代码.
需要注意的一件非常重要的事情是:
域错误处理程序不能代替在发生错误时关闭进程.
根据throw如何在JavaScript中工作的本质,几乎从来没有任何方法可以安全地"拾取你离开的地方",而不会泄漏引用,或者创建一些其他类型的未定义的脆弱状态.
既然你只询问如何回应 (请参阅有关重新启动过程的下一部分)500错误,我就不会像节点文档那样处理如何处理重启服务器等问题.我强烈建议您查看节点文档中的示例.他们的示例演示了如何捕获错误,将错误响应发送回客户端(如果可能),然后重新启动服务器.我将只显示域名创建并发回500错误响应.
域的工作方式类似于在回调中放置try/ .在你的回调中:catchcreateServer
error活动req和res域(因为他们的存在域之前创建)run域并调用您的请求处理程序(这就像/ 的try一部分)trycatch像这样的东西:
var domain = require('domain');
function handleRequest(req, res) {
// Just something to trigger an async error
setTimeout(function() {
throw Error("Some random async error");
res.end("Hello world!");
}, 100);
}
var server = require("http").createServer(function (req, res) {
var d = domain.create();
d.on('error', function(err) {
// We're in an unstable state, so shutdown the server.
// This will only stop new connections, not close existing ones.
server.close();
// Send our 500 error
res.statusCode = 500;
res.setHeader("content-type", "text/plain");
res.end("Server error: " + err.message);
});
// Since the domain was created after req and res, they
// need to be explictly added.
d.add(req);
d.add(res);
// This is similar to a typical try/catch, but the "catch"
// is now d's error event.
d.run(function() {
handleRequest(req, res);
});
}).listen(8080);
Run Code Online (Sandbox Code Playgroud)
通过使用该cluster模块,您可以在发生错误后很好地重新启动该过程.我基本上是从这里的节点文档复制示例,但一般的想法是从主进程启动多个工作进程.worker是处理传入连接的进程.如果其中一个具有不可恢复的错误(即我们在上一节中捕获的错误),那么它将与主进程断开连接,发送500响应并退出.当主进程看到工作进程断开连接时,它将知道发生了错误并启动了新工作程序.由于一次运行多个工作进程,因此如果其中一个连接断开,则不应存在丢失传入连接的问题.
示例代码,从这里复制:
var cluster = require('cluster');
var PORT = +process.env.PORT || 1337;
if (cluster.isMaster) {
// In real life, you'd probably use more than just 2 workers,
// and perhaps not put the master and worker in the same file.
//
// You can also of course get a bit fancier about logging, and
// implement whatever custom logic you need to prevent DoS
// attacks and other bad behavior.
//
// See the options in the cluster documentation.
//
// The important thing is that the master does very little,
// increasing our resilience to unexpected errors.
cluster.fork();
cluster.fork();
cluster.on('disconnect', function(worker) {
console.error('disconnect!');
cluster.fork();
});
} else {
// the worker
//
// This is where we put our bugs!
var domain = require('domain');
// See the cluster documentation for more details about using
// worker processes to serve requests. How it works, caveats, etc.
var server = require('http').createServer(function(req, res) {
var d = domain.create();
d.on('error', function(er) {
console.error('error', er.stack);
// Note: we're in dangerous territory!
// By definition, something unexpected occurred,
// which we probably didn't want.
// Anything can happen now! Be very careful!
try {
// make sure we close down within 30 seconds
var killtimer = setTimeout(function() {
process.exit(1);
}, 30000);
// But don't keep the process open just for that!
killtimer.unref();
// stop taking new requests.
server.close();
// Let the master know we're dead. This will trigger a
// 'disconnect' in the cluster master, and then it will fork
// a new worker.
cluster.worker.disconnect();
// try to send an error to the request that triggered the problem
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
} catch (er2) {
// oh well, not much we can do at this point.
console.error('Error sending 500!', er2.stack);
}
});
// Because req and res were created before this domain existed,
// we need to explicitly add them.
// See the explanation of implicit vs explicit binding below.
d.add(req);
d.add(res);
// Now run the handler function in the domain.
d.run(function() {
handleRequest(req, res);
});
});
server.listen(PORT);
}
// This part isn't important. Just an example routing thing.
// You'd put your fancy application logic here.
function handleRequest(req, res) {
switch(req.url) {
case '/error':
// We do some async stuff, and then...
setTimeout(function() {
// Whoops!
flerb.bark();
});
break;
default:
res.end('ok');
}
}
Run Code Online (Sandbox Code Playgroud)
注意:我仍然要强调您应该查看domain模块文档并查看其中的示例和说明.它解释了大部分(如果不是全部)这个,它背后的原因,以及你可能遇到的其他一些情况.
| 归档时间: |
|
| 查看次数: |
450 次 |
| 最近记录: |