【问题标题】:Node.js Uncaught Exception - Passing more detailsNode.js 未捕获的异常 - 传递更多详细信息
【发布时间】:2018-07-28 08:17:51
【问题描述】:

首先,我知道捕获未捕获错误的一种方法是使用process.on('uncaughtException', err, function() {});

我想知道如何将更多详细信息或更多上下文传递给错误。我希望能够获得使用的变量。我不是试图从错误中恢复,只是在关闭进程之前发生错误时获取我的环境的更多详细信息。是的,堆栈跟踪很好,但我想知道如何复制错误。

比如我有这个功能:

function doTheBatman(var1) {
  var var2 = 'whatever';
  // this causes an uncaught exception later in the code
}

process.on,我希望能够访问var1var2

process.on('uncaughtException', function(err) {
  // process.whatever doesn't contain any active variables
});

【问题讨论】:

  • 你知道你可以add an express route error handler吗?它基本上是使用错误处理函数重载路由定义。
  • 你说得对,我更新了我的问题。我还想从表达上下文中获取函数中存在的变量。
  • I also want to get variables that exist in a function out of the express context - 哪些变量和上下文?快速错误处理程序应该让您访问 req,将其与堆栈跟踪结合起来......我想知道您还需要哪些其他变量来进行诊断?
  • 在我的测试中,当它们发生在不将 req 变量作为论据,至少不使用我上面描述的process.on 方法。变量可以是作为参数传递或在函数内部生成的任何内容。
  • 抱歉,我很难想象与您的快速路线相关的错误发生在哪里,以及哪些数据保存了哪些数据。你能再贴一些代码吗?

标签: node.js


【解决方案1】:

Express 路由处理程序中的同步异常将被 Express 自身捕获,并且该异常将从默认的 Express 错误处理程序传递出去,您可以在其中自己捕获它,并将异常上下文传递给该默认的 Express 错误处理程序。

您可以看到 this code inside of Express 调用路由处理程序的位置:

Layer.prototype.handle_request = function handle(req, res, next) {
  var fn = this.handle;

  if (fn.length > 3) {
    // not a standard request handler
    return next();
  }

  try {
    fn(req, res, next);
  } catch (err) {
    next(err);
  }
};

next(err) 的调用会将异常对象传递给默认的 Express 错误处理程序(you can install a handler for)。


如果您的代码在异步回调中抛出异常,那么在操作中捕获会更加复杂。如果您使用的是常规异步回调(不是承诺),那么我所知道的在有意义的位置捕获这些回调的唯一方法是在每个异步回调中放置一个 try/catch,以便您可以捕获本地堆栈信息。

如果您在最低级别使用 Promise 并且只对您的逻辑进行编程,并且异步代码流使用 Promise 功能,那么 Promise 处理程序中的异常将自动变成被拒绝的 Promise 并且某些 Promise 库(如 Bluebird 库可以配置给你一个非常完整的堆栈跟踪哪里出了问题)。 Promise 有这个优势,因为每个 Promise .then().catch() 处理程序都会自动包装在一个 try/catch 处理程序中,并且这些承诺会转化为 Promise 拒绝,并沿着链传播到他们找到的第一个 .catch() 处理程序。


对于您刚刚添加到问题中的非 Express 示例,您只需在本地附近放置一个 try/catch somehwere 即可捕获本地同步异常:

function doTheBatman(var1) {
  try {
      var var2 = 'whatever';
      // this causes an uncaught exception later in the code
  } catch(e) {
      console.log(e);
  }
}

您甚至可以在catch 处理程序中设置调试器断点,然后在命中该范围时检查该范围内的变量。我不知道有什么方法可以在uncaughtException 处理程序的异常点检查局部变量。 err.stack 应该给你堆栈跟踪,而不是变量值。

【讨论】:

  • 感谢您的回答。我有自己的报告函数,可以在发生错误时接受变量对象,但我必须知道错误何时可能发生。将try...catch 放在我的代码中的每个位置对我来说是不切实际的,但如果我每次编写更多代码时都投入时间和精力去做这件事,从技术上讲是可行的。如果可能的话,我宁愿回退到process.on 并传递变量。
  • 好吧,process.on('uncaughtException, ...)` 将提供err.stack 中的堆栈跟踪,但不会提供堆栈跟踪每个范围内的变量。如果你正在尝试编写一个健壮的服务器,你必须在process.on('uncaughtException, ...)` 之前捕获异常,因为那时你已经失去了在适当的本地上下文中优雅地处理异常的能力。健壮的服务器代码需要 try/catch 处理程序围绕任何具有未经检查的输入或参数或可能引发异常的代码。您要么必须在本地捕获异常,要么阻止异常。
  • 确实如此,对于我的大约 99% 的代码,我执行自己的错误逻辑。但是,我并不完美,有时我会搞砸一些事情,或者我的代码无法捕捉到某些东西。我有process.on 作为报告错误的最后手段。
  • @JM-AGMS - 好吧,看来您要的是一个不存在的功能。我今天只是告诉你它是如何工作的。我理解为什么有人会记录uncaughtException,但这会给你一个堆栈跟踪,这可能需要更多的调试,并且可能需要一些额外的工具来找出首先导致 uncaughtException 的原因,然后最终会导致添加更多@ 987654342@ 将您的代码作为长期解决方案。我也希望 uncaughtException 错误对象能够为您提供解决问题所需的一切,但事实并非如此。
【解决方案2】:

Express/frameworks 可能会提供更优雅/更强大的解决方案,但如果您真的在追问您的问题......为什么不直接捕获函数范围之外的变量呢?这通常是令人讨厌的并且不被认为是最佳实践,但是如果您知道您知道可能经常失败的功能,那么也许您需要快速而肮脏的解决方案。你可以稍后再完善它,但希望这能证明这种方法......

var transactionVars = {};

function clearTransaction() {
  transactionVars = {};
}

function doTheBatman(var1) {
  transactionVars['var2'] = 'whatever';
  // [...] bunch of stuff, possibly blowing up...
  clearTransaction(); // we made it this far? cool, reset...
}

process.on('uncaughtException', function(err) {
  console.log(transactionVars['var2']); // whatever
});

此外,如果您想真的很脏(如果这两个函数在两个文件中),您可以随时在global 对象上添加transactionVars

这本质上是一个糟糕的人事件发射器模式,一旦你掌握了它的工作原理,我强烈建议你重构它......

【讨论】:

  • 哈哈,我想这可以工作并直接在process 上使用它会节省一个步骤,在函数开始时再次重新声明变量也会节省另一个步骤。但是它在我所有的代码上定义try...catch(这将是一个更好的做法)并且需要维护很多错误处理。
  • @JM-AGMS 是的,这取决于你对try...catch 的细致程度我觉得 OCD 级别的错误处理是好的,并且会很好地为你服务。这种方法几乎完全相反,但是如果您在全局“包罗万象”的错误处理程序中找到价值,而不是让您检查有状态变量,那么这就足够了
猜你喜欢
  • 1970-01-01
  • 2020-02-18
  • 1970-01-01
  • 2014-01-24
  • 1970-01-01
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多