从中间件或路由处理程序中调用Express next()
或res.send()
后,是否有任何方法可以捕获异步回调中发生的错误?考虑以下代码:
app.use('/throw-error', (req, res) => {
setTimeout(() => {
throw new Error('Async error causes thread death')
}, 500)
res.send('This thread is going to die...')
})
它将执行并向浏览器发送“此线程将要死...”。半秒钟后,它也会使正在运行的Node线程崩溃。如果您碰巧正在运行一个使用Node的cluster
模块的应用程序,则它可能会启动一个新线程,但仍然死亡。您可能会在日志中看到以下内容:
::1 [2019-07-17T18:54:55.142Z] - [71700] 4.740 ms "GET /throw-error" 200 -
/Users/moryl/Projects/crashtest/express.js:66
throw new Error('Async error causes thread death')
^
Error: Async error causes thread death
at Timeout.setTimeout [as _onTimeout] (/Users/moryl/Projects/InSight/sources/server/config/express.js:66:13)
at ontimeout (timers.js:436:11)
at tryOnTimeout (timers.js:300:5)
at listOnTimeout (timers.js:263:5)
at Timer.processTimers (timers.js:223:10)
该线程现在已死。
我的问题是,您是怎么处理正常请求范围之外的(可能未知的)异步错误的,无论是通过设计还是通过错误处理码?如何防止线程死亡?
我不想被告知我不应该在异步调用中做这种事情。我知道这个。我正在尝试编写防御性代码以捕获其他人编写的“坏东西”。
答案 0 :(得分:3)
这已记录在express
error handling doc中:
您必须捕获路由调用的异步代码中发生的错误 处理程序或中间件,然后将其传递给Express进行处理。对于 例如:
app.get('/', function (req, res, next) { setTimeout(function () { try { throw new Error('BROKEN') } catch (err) { next(err) } }, 100) })
上面的示例使用 try ... catch块来捕获错误, 异步代码并将其传递给Express。 如果try ... catch块 被省略了,Express不会捕获错误,因为它不是一部分 同步处理程序代码。
因此,基本上,您需要try..catch
路线。 (示例基本相同,巧合)
答案 1 :(得分:1)
我的问题是,无论如何设计,您如何处理超出正常请求范围的异步错误...
您仍然希望处理异步代码中的错误,即使该错误已被触发并被设计遗忘。向每个独立任务添加try { } catch { }
或.catch
。使用异步代码,Promises和async
/ await
可以为您提供帮助(它们将独立的回调分组为任务,然后您可以处理每个任务的错误):
const timer = ms => new Promise(res => setTimeout(res, ms));
async function fireAndForgetThis() {
await timer(500);
throw new Error('Async error doesn't cause thread death, because its handled properly')
}
fireAndForgetThis()
.catch(console.error); // But always "handle" errors
...还是通过错误代码?
修正错误代码。
如何防止线程死亡?
这不是您要防止的事情。如果发生错误并且未进行处理,则您的应用程序将进入计划外状态。继续执行可能会产生更多问题。你不要那样您想防止未处理的拒绝/未处理的错误本身(通过正确处理)。
确定在某些情况下您无法处理,例如与备份数据库的连接断开。在这种情况下,NodeJS崩溃,导致监视唤醒DevOps,使数据库重新运行。崩溃也是处理错误;)
的一种形式如果您已读到此,但仍想处理未处理的错误,请不要。好的,您可能有自己的理由,there you go。