如何在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);
答案 0 :(得分:29)
我不知道像Java这样的原生方法,但我还没有找到一个包装错误的优雅解决方案。
创建new Error
的问题是,您可能会丢失附加到抛出的原始Error
的元数据,堆栈和类型通常会留下什么。
对现有错误进行修改的速度更快,但仍然可以修改错误中的数据。在其他地方创建的错误中,它也是错误的。
可以修改新.stack
的{{1}}属性,以便在抛出之前说出您喜欢的内容。完全替换错误Error
属性可能会让调试变得非常混乱。
当原始抛出错误和错误处理程序位于不同的位置或文件中时,您可能能够跟踪原始错误的来源,但不能跟踪实际捕获错误的处理程序。为了避免这种情况,最好在stack
中保留对这两个错误的引用。如果存储了其他元数据,则访问完整的原始错误也很有用。
以下是捕获错误的示例,将其包装在新错误中,但添加原始stack
并存储stack
:
error
引发:
try {
throw new Error('First one')
} catch (error) {
let e = new Error(`Rethrowing the "${error.message}" error`)
e.original = 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
之外,新的stack
已基本删除。
任何尝试解析堆栈跟踪的工具都可能无法使用此更改或最佳情况,它们会检测到两个错误。
将其变成可重复使用的ES2015 +错误类......
stack
结果
// Standard error extender from @deployable/errors
class ExtendedError extends Error {
constructor(message){
super(message)
this.name = this.constructor.name
this.message = message
if (typeof Error.captureStackTrace === 'function'){
Error.captureStackTrace(this, this.constructor)
} else {
this.stack = (new Error(message)).stack
}
}
}
class RethrownError extends ExtendedError {
constructor(message, error){
super(message)
if (!error) throw new Error('RethrownError requires a message and error')
this.original = error
this.new_stack = this.stack
let 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
仍然可以使用原始错误。
这种方法并不完美,但这意味着我可以将基础模块中的已知错误输入到更容易处理的泛型类型中,通常使用蓝鸟filtered catch .catch(TypeError, handler)
有时您需要保持原始错误。
在这种情况下,您只需将新信息附加/插入现有堆栈即可。
.original
返回
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)
来终止消息。
答案 1 :(得分:6)
如果您只想更改消息,则只需更改消息:
try {
throw new Error("Original Error");
} catch(err) {
err.message = "Here is some context -- " + err.message;
throw err;
}
&#13;
答案 2 :(得分:2)
您也可以继续将错误抛到试用链上。如果你想修改任何东西:b。
中的throw语句之前
function a() {
throw new Error('my message');
}
function b() {
try {
a();
} catch (e) {
// add / modify properties here
throw e;
}
}
function c() {
try {
b();
} catch (e) {
console.log(e);
document.getElementById('logger').innerHTML = e.stack;
}
}
c();
<pre id="logger"></pre>
答案 3 :(得分:0)
您可能想看看Joyent的verror module,它提供了一种包装错误的简便方法:
var originError = new Error('No such file or directory');
var err = new VError(originError, 'Failed to load configuration');
console.error(err.message);
这将打印:
Failed to load configuration: No such file or directory