mongodb在try catch中出现异常崩溃的节点

Posted

技术标签:

【中文标题】mongodb在try catch中出现异常崩溃的节点【英文标题】:mongodb crashed node with exception within try catch 【发布时间】:2013-11-29 11:49:57 【问题描述】:
try
    p = req.params.name
    Item.update('name': p, req.body , upsert: true, (err) ->
      if err?
        throw err
      res.send("ok")
      )
  catch e
    handle_error(e, "Error salvando hoja de vida.", res)

这会在我的代码中产生一个错误 - 没关系,但是为什么即使我在这里尝试捕获,我的 nodejs 程序也会崩溃?

错误是:

MongoError: Mod on _id not allowed

(所以它必须在更新调用中) 我正在专门寻找一种方法来捕获错误,我已经知道如何摆脱它。

【问题讨论】:

【参考方案1】:

啊,是的,你已经进入了异步代码的领域。将回调传递给 MongoDB 调用(如 Item.update(..., callback))的原因是因为 MongoDB 驱动程序是异步编写的。考虑一下(猫鼬代码):

var user = User.findOne( name: 'joe' );
doSomethingElse();

如果它的 API 结构类似于上述代码,那么您的整个应用程序将停止,直到 User.findOne() 从数据库返回结果。在检索到用户之前不会调用您的doSomethingElse() 调用,即使您没有对doSomethingElse 中的user 执行任何操作。这些天来这是一个很大的禁忌,尤其是在尽可能异步编写的节点中。请看以下内容:

User.findOne( name: 'joe' , function (err, user) 
    if (err) return console.error(err);
    console.log('Do stuff with user... ;)');
);
doSomethingElse();

上面的代码是异步的。 findOne 函数返回立即 并且doSomethingElse 甚至可以在从数据库中检索到用户之前开始。但是当然我们仍然想和我们的用户做一些事情,所以为了完成这个我们传入一个匿名函数作为回调。 MongoDB 驱动程序足够智能,可以在完成检索数据后调用该函数。

将上述代码包装在 try/catch 中是没有意义的,除非您怀疑 findOne 函数会引发异常(您不应该这样做。它会立即返回还记得吗?)。

try 
    User.findOne( name: 'joe' , function (err, user) 
        throw new Error("Something went wrong...");
    );
 catch (err) 
    console.error(err);

上述错误仍然会使您的程序崩溃,因为它发生在findOne 返回之后很久,并且您的程序超出了宝贵的 try/catch。这就是您的回调函数接收err 参数的原因。 MongoDB 驱动程序知道,如果在获取数据时发生错误,那么抛出异常并称其为好是没有好处的。这是因为所有这些处理都发生在事件循环的后续行程中,在几次迭代之前将您的 try/catch 抛在后面。

为了解决这个问题,MongoDB 驱动程序将它自己的内部同步代码包装在一个 try/catch 中,它实际上将在其中处理异常,然后它调用您的回调,将错误作为第一个参数传入。这使您可以检查该参数并处理回调中的任何错误。

我写了一篇完整的博客文章来解释回调,以及另一种处理异步代码的方法,称为“承诺”,我认为它会帮助你澄清一些事情:) http://codetunnel.io/what-are-callbacks-and-promises

我希望这有助于回答您的问题。

【讨论】:

感谢@Alex,它很好地解释了一切——但对我来说,有些事情仍然是个谜。如果,如您所说,MongoDB“将自己的内部异步代码包装在一个 try/catch 中,它实际上将处理异常,然后它调用您的回调,将错误作为第一个参数传递。” - 为什么程序会因为一个相对无害的错误而完全崩溃,例如“MongoError: Mod on _id not allowed”。这就是为什么我首先尝试捕获的原因......我不希望我的程序崩溃! oops - 我猜是因为我重新抛出错误,期望它被周围的 try/catch 捕获...... 答案中有死链接 @StepanYakovenko 给你 :) codetunnel.io/what-are-callbacks-and-promises【参考方案2】:

也许我错了(因为我不知道 Coffeescript),但我想问题是,你的 try/catch 在回调函数之外。捕获不会影响您的err ->,因此异常不是由您捕获,而是由 node.js 捕获。

如果我错了,能否提供编译后的 javascript 代码?

编辑

通常人们会像这样处理错误(没有 try/catch):

Item.update('name': p, req.body , upsert: true, (err) ->
  if err?
    log.error('error updating Item name=' + name)
    res.status(500).end()
    return
  res.send("ok")
  )

您的handle_error 可能已经这样做了。

在 node.js 中编程时,我仅将 try/catch 用于JSON.parse,或者如果我有很多未经检查的输入,这些输入可能有错误的类型或可能为 null,我也是懒得手动检查所有输入。仅当函数存在编程错误(例如,未正确检查您的输入)时,使用 try/catch 包围异步函数才有用。

【讨论】:

以上是关于mongodb在try catch中出现异常崩溃的节点的主要内容,如果未能解决你的问题,请参考以下文章

“崩溃了?不可能,我全 Catch 住了” | Java 异常处理

为啥使用Try,Catch捕获异常,程序依然Crash

java中try 与catch的使用

Java学习笔记之三十三详解Java中try,catch,finally的用法及分析

JAVA中try catch捕获异常的问题

try-catch语句