如何在nodejs/javascript中重新显示错误或异常,并包含自定义消息.

我有以下代码

var json = JSON.parse(result);

如果出现任何解析错误,我想在异常消息中包含result个内容.像这样的.

1.  try {
2.    var json = JSON.parse(result);
3.    expect(json.messages.length).to.be(1);
4.  } catch(ex) {
5.    throw new Error(ex.message + ". " + "JSON response: " + result);
6.  }

这里的问题是我丢失了堆栈跟踪.

有没有类似于java的方法?

throw new Error("JSON response: " + result, ex);

推荐答案

我不知道有像Java这样的本机方法,我还没有找到包装错误的优雅解决方案.

创建new Error的问题是,可能会丢失附加到抛出的原始Error的元数据,堆栈跟踪和类型通常是丢失的重要项.

对现有抛出的错误进行修改更快,但仍然可以在错误不存在的情况下修改数据.在其他地方产生的错误中到处乱翻也会让人感觉不对劲.

创建新错误和新堆栈

Error.stack属性是一个普通字符串,可以在抛出之前进行修改,以说出您喜欢的内容.但是,完全替换errors stack属性会让调试变得非常混乱.

当原始抛出的错误和错误处理程序位于不同的位置或文件(这在promises中很常见)时,您可能可以跟踪原始错误的来源,但无法跟踪错误实际被捕获的处理程序.为了避免这种情况,最好在stack中保留一些对原始错误和新错误的引用.如果原始错误中存储了其他元数据,那么访问完整的原始错误也很有用.

下面是一个捕获错误的示例,将其包装为新错误,但添加原来的stack并存储error:

try {
  throw new Error('First one')
} catch (error) {
  let e = new Error(`Rethrowing the "${error.message}" error`)
  e.original_error = error
  e.stack = e.stack.split('\n').slice(0,2).join('\n') + '\n' +
            error.stack
  throw e
}

它抛出:

/so/42754270/test.js:9
    throw e
    ^

Error: Rethrowing the "First one" error
    at test (/so/42754270/test.js:5:13)
Error: First one
    at test (/so/42754270/test.js:3:11)
    at Object.<anonymous> (/so/42754270/test.js:13:1)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)

所以我们创造了一个新的通用Error.不幸的是,原始错误的类型在输出中被隐藏,但error已被附加为.original_error,因此仍然可以访问.除了重要的生成线和附加的原始错误stack之外,新的stack基本上被删除.

任何试图解析堆栈跟踪的工具都可能无法处理此更改或最佳情况,它们检测到两个错误.

使用ES2015+错误类重新刷新

使其成为可重用的ES2015+错误类:

class RethrownError extends Error {
  constructor(message, error){
    super(message)
    this.name = this.constructor.name
    if (!error) throw new Error('RethrownError requires a message and error')
    this.original_error = error
    this.stack_before_rethrow = this.stack
    const message_lines =  (this.message.match(/\n/g)||[]).length + 1
    this.stack = this.stack.split('\n').slice(0, message_lines+1).join('\n') + '\n' +
                 error.stack
  }
}

throw new RethrownError(`Oh no a "${error.message}" error`, error)

结果

/so/42754270/test2.js:31
    throw new RethrownError(`Oh no a "${error.message}"" error`, error)
    ^

RethrownError: Oh no a "First one" error
    at test (/so/42754270/test2.js:31:11)
Error: First one
    at test (/so/42754270/test2.js:29:11)
    at Object.<anonymous> (/so/42754270/test2.js:35:1)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)

然后你知道,每当你看到一个RethrownError,原来的错误仍然会在.original_error可用.

这种方法并不完美,但它意味着我可以将底层模块中的已知错误重新类型化为更容易处理的泛型类型,通常使用Bluebird filtered catch .catch(TypeError, handler)

Notestack在这里成为可枚举的

修改后的堆栈也会出现同样的错误

有时,你需要保持原始错误基本不变.

在这种情况下,您可以将新信息附加/插入到现有堆栈中.

file = '/home/jim/plumbers'
try {
   JSON.parse('k')
} catch (e) {
   let message = `JSON parse error in ${file}`
   let stack = new Error(message).stack
   e.stack = e.stack + '\nFrom previous ' + stack.split('\n').slice(0,2).join('\n') + '\n'
   throw e
}

它回来了

/so/42754270/throw_error_replace_stack.js:13
       throw e
       ^

SyntaxError: Unexpected token k in JSON at position 0
    at Object.parse (native)
    at Object.<anonymous> (/so/42754270/throw_error_replace_stack.js:8:13)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)
From previous Error: JSON parse error in "/home/jim/plumbers"
    at Object.<anonymous> (/so/42754270/throw_error_replace_stack.js:11:20)

还要注意,堆栈处理很简单,并且假设错误消息是单行.如果遇到多行错误消息,可能需要查找\n at 以终止消息.

Node.js相关问答推荐

如何使用Express正确跟踪服务器应用程序上的所有传出的Node.js请求

try 使用Puppeteer抓取Twitter时数组空

如何在node.js中以随机顺序调用函数并按顺序操作

无法从MongoDB文档中保存的对象数组中获取对象的属性

如何模拟 mysql2 `getConnection`

Gulp 能否向 Docker 发出增量构建的第一次迭代完成的信号?

结合后端(Express)和前端(Angular)路由

看起来这段代码try GET 请求发送的值变为空白

firebase/messaging 不提供名为 getToken 的导出

Cassandra node.js 驱动程序有替代品吗?

如何在 node.js 环境中从 WebAssembly (Rust) 调用异步 JavaScript 导入函数?

如果我使用像 express 这样的 node 服务器,是否需要 webpack-dev-server

如何使用 Puppeteer 从输入中删除现有文本?

在 PassportJS 中使用多种本地策略

无法获取 CSS 文件

在 express 中添加故意延迟

向 Stripe 提交付款请求时出现没有此类令牌错误

nodejs:Ajax 与 Socket.IO,优缺点

大型项目的 NodeJS vs Play 框架

npm install packagename --save-dev 不更新 package.json