N'est-il pas possible de stringify une Erreur en utilisant JSON.stringify?
De reproduire le problème
Je suis en cours d'exécution dans un problème lorsque vous essayez de transmettre des messages d'erreur autour de l'utilisation des sockets web. Je peux reproduire le problème, je suis confronté à l'aide de JSON.stringify
pour répondre à un public plus large:
//node v0.10.15
> var error = new Error('simple error message');
undefined
> error
[Error: simple error message]
> Object.getOwnPropertyNames(error);
[ 'stack', 'arguments', 'type', 'message' ]
> JSON.stringify(error);
'{}'
Le problème est que je me retrouve avec un objet vide.
Ce que j'ai essayé
Navigateurs
J'ai d'abord essayé de quitter node.js et en cours d'exécution dans les différents navigateurs. La version Chrome 28 me donne le même résultat, et qui est assez intéressant, Firefox au moins fait une tentative, mais à gauche du message:
>>> JSON.stringify(error); //Firebug, Firefox 23
{"fileName":"debug eval code","lineNumber":1,"stack":"@debug eval code:1\n"}
Fonction Replacer
J'ai alors regardé les Erreur.prototype. Il montre que le prototype contient des méthodes telles que toString et toSource. Sachant que les fonctions ne peuvent pas être stringified, j'ai inclus une fonction replacer lors de l'appel de JSON.stringify pour supprimer toutes les fonctions, mais alors réalisé qu'il avait un étrange comportement:
var error = new Error('simple error message');
JSON.stringify(error, function(key, value) {
console.log(key === ''); //true (?)
console.log(value === error); //true (?)
});
Il ne semble pas en boucle sur l'objet comme il le ferait normalement, et donc je ne peux pas vérifier si la clé est une fonction et de l'ignorer.
La Question
Est-il possible de stringify natif des messages d'Erreur avec JSON.stringify
? Si non, pourquoi ce comportement ne se produisent?
Méthodes de contourner ce
- Bâton avec simple basé sur des chaînes de messages d'erreur, ou de créer des objets d'erreur et ne comptez pas sur l'objet Error natif.
- Pull propriétés:
JSON.stringify({ message: error.message, stack: error.stack })
Mises à jour
@Ray Toal Suggéré dans un commentaire que je prends un coup d'oeil à la propriété des descripteurs. Il est clair maintenant pourquoi il ne fonctionne pas:
var error = new Error('simple error message');
var propertyNames = Object.getOwnPropertyNames(error);
var descriptor;
for (var property, i = 0, len = propertyNames.length; i < len; ++i) {
property = propertyNames[i];
descriptor = Object.getOwnPropertyDescriptor(error, property);
console.log(property, descriptor);
}
De sortie:
stack { get: [Function],
set: [Function],
enumerable: false,
configurable: true }
arguments { value: undefined,
writable: true,
enumerable: false,
configurable: true }
type { value: undefined,
writable: true,
enumerable: false,
configurable: true }
message { value: 'simple error message',
writable: true,
enumerable: false,
configurable: true }
Clés: enumerable: false
.
Accepté de répondre fournit une solution de contournement pour ce problème.
- Avez-vous examiné la propriété des descripteurs pour les propriétés de l'objet d'erreur?
- La question pour moi était "pourquoi", et j'ai trouvé la réponse se trouvait au fond de la question. Il n'y a rien de mal à poster une réponse à votre propre question, et vous obtiendrez probablement plus de cred de cette façon. 🙂
Vous devez vous connecter pour publier un commentaire.
Vous pouvez définir un
Error.prototype.toJSON
pour récupérer une plaineObject
représentant leError
:À l'aide de
de l'Objet.defineProperty()
ajoutetoJSON
sans qu'il soit unenumerable
de la propriété elle-même.Concernant la modification de
Error.prototype
, tandis quetoJSON()
ne peut pas être définie pourError
s spécifiquement, la méthode est encore normalisé pour les objets en général (ref: étape 3). Ainsi, le risque de collisions ou de conflits est minime.Si, pour éviter encore complètement,
JSON.stringify()
dupoudre
paramètre peut être utilisée à la place:.getOwnPropertyNames()
au lieu de.keys()
, vous aurez la non-énumérable propriétés sans avoir à les définir manuellement..keys()
est de "propre" propriétés ainsi. Pensé qu'il pourrait inclure hérité.var error2 = new Error2(error)
et puisJSON.stringify(error2)
.writable: true
devrait résoudre ce problème.Error.prototype.toJSON
technique? C'est un stringified pile d'appel, mais une pile d'appel pour vous.key
dansfunction replaceErrors(key, value)
pour éviter de nommer en conflit avec.forEach(function (key) { .. })
; lareplaceErrors
key
paramètre n'est pas utilisé dans cette réponse.semble fonctionner
[à partir d'un commentaire par /u/ub3rgeek sur /r/javascript] et felixfbecker de commentaire ci-dessous
JSON.stringify(err, Object.getOwnPropertyNames(err))
ValidationError
types. Ce ne sera pas stringify imbriquéeerrors
objet dans une Mangouste objet d'erreur de typeValidationError
.var spam = { a: 1, b: { b: 2, b2: 3} };
et exécuterObject.getOwnPropertyNames(spam)
, vous aurez["a", "b"]
-- trompeur ici, parce que leb
objet a sa propreb
. Vous obtiendrez à la fois dans votre stringify appel, mais vous raterspam.b.b2
. C'est un mauvais.message
etstack
sont inclus dans le JSON.message
etstack
propriétés directement?La modification de Jonathan grande réponse pour éviter le monkey patching:
monkey patching
🙂toJSON
, directement àError
s'prototype, qui n'est pas souvent une bonne idée. Peut-être que quelqu'un d'autre l'a déjà fait, ce qui ce vérifie, mais vous ne savez pas ce que les autres version ne. Ou si quelqu'un de façon inattendue obtient le vôtre, ou assume l'Erreur du prototype possède des propriétés spécifiques, les choses pourraient bork.)Que personne ne parle de la pourquoi partie, je vais y répondre.
Pourquoi cette
JSON.stringify
retourne un objet vide?Réponse
Dans le document de JSON.stringify(),
et
Error
objet de ne pas avoir ses propriétés énumérables, c'est pourquoi il imprime un objet vide.JSON.stringify
à l'aide de sonreplacer
paramètre.Il y a une grande Node.js paquet pour que:
serialize-error
.Il gère bien, même imbriquée objets d'Erreur, ce que j'ai fait j'ai besoin dans mon projet.
https://www.npmjs.com/package/serialize-error
Vous pouvez aussi redéfinir ces non-énumérable propriétés énumérables.
et peut-être
stack
bien trop.Aucune des réponses ci-dessus semble correctement sérialiser des propriétés qui sont sur le prototype d'Erreur (parce que
getOwnPropertyNames()
ne comprend pas les propriétés héritées). J'ai aussi été pas en mesure de redéfinir les propriétés comme l'une des réponses proposées.C'est la solution, je suis venu avec - il utilise lodash mais vous pouvez le remplacer lodash avec des versions génériques de ces fonctions.
Voici le test que j'ai fait dans Chrome:
Nous avons besoin de serialise un objet arbitraire de la hiérarchie, où la racine ou l'une des propriétés imbriquées dans la hiérarchie pouvait y avoir des cas d'Erreur.
Notre solution a été d'utiliser le
replacer
param deJSON.stringify()
, par exemple:JS: