从 Node.JS 中的未捕获异常中恢复
Posted
技术标签:
【中文标题】从 Node.JS 中的未捕获异常中恢复【英文标题】:Recover from Uncaught Exception in Node.JS 【发布时间】:2011-12-28 05:39:51 【问题描述】:好的,所以我有一个问题。如果在处理 HTTP 请求时发生未捕获的异常,我没有机会调用 http.ServerResponse 对象的 end() 方法。因此,服务器永远挂起并且永远不会满足请求。
这是一个例子:
var express = require('express');
var app = express.createServer();
var reqNum = 0;
app.get('/favicon.ico', function(req, res) res.send(404););
app.get('*', function(req, res, next)
console.log("Request #", ++reqNum, ":", req.url);
next();
);
app.get('/error', function(req, res, next)
throw new Error("Problem occurred");
);
app.get('/hang', function(req, res, next)
console.log("In /hang route");
setTimeout(function()
console.log("In /hang callback");
if(reqNum >= 3)
throw new Error("Problem occurred");
res.send("It worked!");
, 2000);
);
process.on('uncaughtException', function(err)
console.log("Uncaught exception!", err);
);
app.listen(8080);
如果你访问/error,就会发生异常,但是会被捕获。用户收到一条错误消息 - 没问题。但是,如果我访问 /hang,服务器最终将抛出未捕获的异常并永远挂起。任何后续的 /hang 请求都将挂起。
这很糟糕。有关如何解决此问题的任何建议?
【问题讨论】:
【参考方案1】:当发生未捕获的异常时,您处于不干净状态。让进程终止并重新启动它,您无法安全地将其恢复到已知良好状态。使用forever
,它会在它死后立即重新启动你的进程。
【讨论】:
我在一定程度上同意。在生产环境中,您不能仅仅因为一个未捕获的异常而真正关闭整个服务器。如果单个 php 页面出现问题怎么办?你的整个网络服务器会宕机吗?如果发生未捕获的异常,我将让服务器向我发送电子邮件,如果在 60 秒内发生超过 10 个异常,我将自动关闭。但是,真的......我不希望服务器停机并重新启动。我想尝试恢复。 @BMiner 重新启动您的应用程序比向客户道歉他们的数据损坏更容易。正如 thejh 所说,运行时处于不干净状态。从现在开始,您应该假设一切都是未定义的行为。 @thejh 为什么我必须假设我处于不洁状态?也许只有程序的一部分被破坏了?为什么关闭并重新启动更安全?我相信你们,但我仍然持怀疑态度。你能举个例子吗? @BMiner:你说的是“也许”。问题是,throw
就像 GOTO,当事情完成一半时它会跳出你的代码,现在你的状态可能已经损坏。示例:user.name = newname; db.save(user.id, 'name', newname)
- 如果db.save
在完成之前中断怎么办?您的 DB 包含的名称与您在 RAM 中的名称不同。
完全同意@thejh,您应该让进程立即终止(以避免数据损坏等),然后重新启动您的服务器。【参考方案2】:
如果同步抛出错误,express不会停止工作,只返回500。
this.app.get("/error", (request, response) =>
throw new Error("shouldn't stop");
);
如果异步抛出错误,express 会崩溃。但是根据它的official documentation,还是有办法恢复的,调用next
:
this.app.get("/error", (request, response, next) =>
setTimeout(() =>
try
throw new Error("shouldn't stop");
catch (err)
next(err);
, 0);
);
这将使 express 尽其职责以 500 错误响应。
【讨论】:
【参考方案3】:使用 try/catch/finally。
app.get('/hang', function(req, res, next)
console.log("In /hang route");
setTimeout(function()
console.log("In /hang callback");
try
if(reqNum >= 3)
throw new Error("Problem occurred");
catch (err)
console.log("There was an error", err);
finally
res.send("It worked!");
, 2000);
);
【讨论】:
丑陋但实用以上是关于从 Node.JS 中的未捕获异常中恢复的主要内容,如果未能解决你的问题,请参考以下文章
无效更新:第 0 节中的无效行数以 NSException 类型的未捕获异常终止
从 Swit2.3 到 Swift3 的转换导致“以 NSException 类型的未捕获异常终止”