Comment puis-je renvoyer une erreur ou une exception dans nodejs/javascript et inclure un message personnalisé.
J'ai le code suivant
var json = JSON.parse(result);
et je voulais inclure le contenu result
dans le message d'exception en cas d'erreur d'analyse syntaxique. Quelque chose comme ça.
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. }
Le problème ici est que je perds ma trace de pile.
Existe-t-il un moyen de le faire similaire à Java
?
throw new Error("JSON response: " + result, ex);
Je ne connais pas de méthode native comme Java et je n'ai pas encore trouvé de solution élégante pour envelopper les erreurs.
Le problème avec la création d'un new Error
Est que vous pouvez perdre des métadonnées attachées au Error
d'origine qui a été jeté, la trace et le type de pile sont généralement les éléments importants perdus.
Il est plus rapide d'apporter des modifications à une erreur levée existante, mais il est toujours possible de modifier les données de l'erreur hors de son existence. Il semble également mal de fouiller dans une erreur qui a été créée ailleurs.
La propriété .stack
D'un nouveau Error
est une chaîne simple et peut être modifiée pour dire ce que vous aimez avant qu'elle ne soit lancée. Le remplacement complet d'une propriété stack
d'erreurs peut cependant être très déroutant pour le débogage.
Lorsque l'erreur levée d'origine et le gestionnaire d'erreurs se trouvent dans des emplacements ou des fichiers distincts (ce qui est courant avec les promesses), vous pouvez peut-être tracer la source de l'erreur d'origine mais pas tracer le gestionnaire où l'erreur a été réellement interceptée. Pour éviter cela, il est bon de conserver quelques références à la fois à l'erreur d'origine et à la nouvelle dans le stack
. Il est également utile d'avoir accès à l'erreur d'origine complète si des métadonnées supplémentaires y étaient stockées.
Voici un exemple de capture d'une erreur, de l'encapsuler dans une nouvelle erreur mais en ajoutant le stack
d'origine et en stockant le 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
}
Ce qui jette:
/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)
Nous avons donc créé un nouveau générique Error
. Malheureusement, le type de l'erreur d'origine est masqué dans la sortie, mais le error
a été attaché en tant que .original
Afin qu'il soit toujours accessible. Le nouveau stack
a été en grande partie supprimé, à l'exception de la ligne de génération qui est importante, et les erreurs d'origine stack
ont été ajoutées.
Tous les outils qui tentent d'analyser les traces de pile peuvent ne pas fonctionner avec cette modification ou, dans le meilleur des cas, ils détectent deux erreurs.
Transformation en une classe d'erreur ES2015 + réutilisable ...
// 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)
Résulte en
/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)
Vous savez alors qu'à chaque fois que vous voyez un RethrownError
que l'erreur d'origine sera toujours disponible dans .original
.
Cette méthode n'est pas parfaite, mais cela signifie que je peux retaper les erreurs connues des modules sous-jacents en types génériques qui peuvent être traités plus facilement, généralement avec des oiseaux bleus catch filtré .catch(TypeError, handler)
Parfois, vous devrez conserver l'erreur d'origine en grande partie telle quelle.
Dans ce cas, vous pouvez simplement ajouter/insérer les nouvelles informations sur la pile existante.
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
}
Qui revient
/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)
Notez également que le traitement de la pile est simple et suppose que le message d'erreur est une seule ligne. Si vous rencontrez des messages d'erreur sur plusieurs lignes, vous devrez peut-être rechercher \n at
Pour terminer le message.
Si tout ce que vous voulez faire est de changer le message, vous pouvez simplement changer le message:
try {
throw new Error("Original Error");
} catch(err) {
err.message = "Here is some context -- " + err.message;
throw err;
}
vous pouvez également continuer à lancer l'erreur dans votre chaîne d'essai. Si vous souhaitez modifier quoi que ce soit, faites-le en cours de route: avant l'instruction throw en b.
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>
Vous voudrez peut-être jeter un œil au module verror de Joyent, qui fournit un moyen facile de récapituler les erreurs:
var originError = new Error('No such file or directory');
var err = new VError(originError, 'Failed to load configuration');
console.error(err.message);
Cela imprimera:
Failed to load configuration: No such file or directory