gpt4 book ai didi

javascript - 处理 http 服务器崩溃

转载 作者:数据小太阳 更新时间:2023-10-29 05:57:49 25 4
gpt4 key购买 nike

我有一个非常基本的 http 服务器:

require("http").createServer(function (req, res) {
res.end("Hello world!");
}).listen(8080);

如何监听服务器崩溃以便发送 500 状态代码作为响应?

监听 process.on("uncaughtException", handler)process 级别工作,但我没有请求和响应对象。

我看到的一个可能的解决方案是在 createServer 回调中使用 try - catch 语句,但我正在寻找是否有更好的解决方案。

我尝试在 server 对象上监听 error 事件,但没有任何反应:

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);

最佳答案

捕获并处理错误

您可以使用 Node 的内置 domain module为了这。

Domains provide a way to handle multiple different IO operations as a single group. If any of the event emitters or callbacks registered to a domain emit an error event, or throw an error, then the domain object will be notified, rather than losing the context of the error in the process.on('uncaughtException') handler, or causing the program to exit immediately with an error code.

需要注意的一件非常重要的事情是:

Domain error handlers are not a substitute for closing down your process when an error occurs.

By the very nature of how throw works in JavaScript, there is almost never any way to safely "pick up where you left off", without leaking references, or creating some other sort of undefined brittle state.

由于您只是询问如何响应 500 错误,因此我不会深入探讨如何处理重启服务器等,例如 Node 文档确实如此; 我强烈推荐 taking a look at the example in the node docs 。他们的示例展示了如何捕获错误,将错误响应发送回客户端(如果可能),然后重新启动服务器。我将只展示域创建和发回 500 错误响应。 (请参阅下一节关于重新启动该过程)

域的工作方式类似于将 try/catch 放入您的 createServer 回调中。在你的回调中:

  1. 创建一个新的域对象
  2. 监听域的错误事件
  3. reqres 添加到域中(因为它们是在域存在之前创建的)
  4. run 域并调用您的请求处理程序(这就像 try/catchtry 部分>)

像这样:

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);

出错后重启进程

通过使用 cluster 模块,您可以在出错后很好地重新启动进程。我基本上是从此处的 Node 文档中复制示例,但总体思路是从主进程启动多个工作进程。工作人员是处理传入连接的进程。如果其中一个有不可恢复的错误(即我们在上一节中捕获的错误),那么它将与主进程断开连接,发送 500 响应,然后退出。当主进程看到工作进程断开连接时,它会知道发生了错误并启动了一个新的工作进程。由于有多个工作进程同时运行,因此如果其中一个出现故障,应该不会出现丢失传入连接的问题。

示例代码,复制自 here :

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');
}
}

注意:我还是要强调,你应该看看domain module documentation并查看那里的示例和解释。它解释了大部分(如果不是全部)、其背后的原因以及您可能会遇到的其他一些情况。

关于javascript - 处理 http 服务器崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25957449/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com