Reproduire le problème
Je rencontre un problème lorsque j'essaie de transmettre des messages d'erreur concernant l'utilisation des sockets Web. Je peux reproduire le problème auquel je fais face 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 de l'exécuter dans divers navigateurs. La version 28 de Chrome me donne le même résultat et, chose intéressante, Firefox fait au moins une tentative mais laisse de côté le message:
>>> JSON.stringify(error); // Firebug, Firefox 23
{"fileName":"debug eval code","lineNumber":1,"stack":"@debug eval code:1\n"}
Fonction de remplacement
J'ai ensuite regardé le prototype Error.prototype . Il montre que le prototype contient des méthodes telles que toString et toSource . Sachant que les fonctions ne peuvent pas être stringifiées, j'ai inclus une fonction de remplacement lors de l'appel de JSON.stringify pour supprimer toutes les fonctions, mais ensuite réalisé qu'elle avait également un comportement étrange:
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 boucler sur l'objet comme il le ferait normalement, et donc je ne peux pas vérifier si la clé est une fonction et l'ignorer.
La question
Existe-t-il un moyen de filtrer les messages d'erreur natifs avec JSON.stringify
? Sinon, pourquoi ce problème se produit-il?
Méthodes pour contourner ce problème
- Restez avec des messages d'erreur simples basés sur des chaînes ou créez des objets d'erreur personnels et ne vous fiez pas à l'objet d'erreur natif.
- Propriétés de traction:
JSON.stringify({ message: error.message, stack: error.stack })
Mises à jour
@Ray Toal Suggéré dans un commentaire que je regarde les descripteurs de propriété . Il est maintenant clair pourquoi cela 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);
}
Production:
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 }
Key: enumerable: false
.
La réponse acceptée fournit une solution de contournement à ce problème.
la source
Réponses:
Vous pouvez définir un
Error.prototype.toJSON
pour récupérer une plaineObject
représentantError
:Utiliser
Object.defineProperty()
ajoutetoJSON
sans que ce soit uneenumerable
propriété elle-même.En ce qui concerne la modification
Error.prototype
, même si elletoJSON()
ne peut pas être définieError
spécifiquement pour s, la méthode est toujours normalisée pour les objets en général (réf: étape 3). Ainsi, le risque de collisions ou de conflits est minime.Cependant, pour l'éviter complètement,
JSON.stringify()
lereplacer
paramètre de peut être utilisé à la place:la source
.getOwnPropertyNames()
au lieu de.keys()
, vous obtiendrez les propriétés non énumérables sans avoir à les définir manuellement.key
infunction replaceErrors(key, value)
afin d'éviter tout conflit de dénomination avec.forEach(function (key) { .. })
; lereplaceErrors
key
paramètre n'est pas utilisé dans cette réponse.key
dans cet exemple, bien qu'autorisée, est potentiellement déroutante car elle laisse planer le doute quant à savoir si l'auteur avait l'intention de se référer à la variable externe ou non.propName
serait un choix plus expressif pour la boucle intérieure. (BTW, je pense que @ 404NotFound signifiait « linter » (outil d'analyse statique) pas « linker » ) Dans tous les cas, en utilisant une coutumereplacer
fonction est une excellente solution pour cela car il résout le problème en un seul, le lieu approprié et ne modifie pas natif / comportement global.semble fonctionner
[ extrait d'un commentaire de / u / ub3rgeek sur / r / javascript ] et du commentaire de felixfbecker ci-dessous
la source
JSON.stringify(err, Object.getOwnPropertyNames(err))
ValidationError
types. Cela ne stringifiera pas l'errors
objet imbriqué dans un objet d'erreur Mongoose de typeValidationError
.var spam = { a: 1, b: { b: 2, b2: 3} };
et courezObject.getOwnPropertyNames(spam)
, vous serez["a", "b"]
trompé ici, car l'b
objet a le sienb
. Vous obtiendrez les deux dans votre appel stringify, mais vous manqueriezspam.b.b2
. C'est mauvais.message
etstack
sont inclus dans le JSON.Comme personne ne parle de la partie pourquoi , je vais y répondre.
Pourquoi cela
JSON.stringify
renvoie un objet vide?Répondre
Du document de JSON.stringify () ,
et l'
Error
objet n'a pas ses propriétés énumérables, c'est pourquoi il imprime un objet vide.la source
JSON.stringify
sonreplacer
paramètre.Modification de la bonne réponse de Jonathan pour éviter les correctifs de singe:
la source
monkey patching
:)toJSON
, directement auError
prototype de » , qui est souvent pas une bonne idée. Peut - être que quelqu'un d' autre a déjà, qui ce contrôle, mais vous ne savez pas ce que cette autre version le fait. Ou si quelqu'un obtient le vôtre de façon inattendue, ou suppose que le prototype d'Erreur a des propriétés spécifiques, les choses pourraient s'arrêter.)Il existe un excellent package Node.js pour cela:
serialize-error
.Il gère bien même les objets Error imbriqués, ce dont j'avais réellement besoin dans mon projet.
https://www.npmjs.com/package/serialize-error
la source
Vous pouvez également simplement redéfinir ces propriétés non énumérables pour qu'elles soient énumérables.
et peut-être
stack
aussi la propriété.la source
Nous avions besoin de sérialiser une hiérarchie d'objets arbitraires, où la racine ou l'une des propriétés imbriquées dans la hiérarchie pourrait être des instances d'Erreur.
Notre solution a été d'utiliser les
replacer
paramètres deJSON.stringify()
, par exemple:la source
Aucune des réponses ci-dessus ne semble sérialiser correctement les propriétés qui se trouvent sur le prototype de l'erreur (car
getOwnPropertyNames()
n'inclut pas les propriétés héritées). Je n'ai pas non plus été en mesure de redéfinir les propriétés comme l'une des réponses suggérées.C'est la solution que j'ai trouvée - elle utilise lodash mais vous pouvez remplacer lodash par des versions génériques de ces fonctions.
Voici le test que j'ai fait dans Chrome:
la source
Je travaillais sur un format JSON pour les ajouts de journaux et j'ai fini par essayer de résoudre un problème similaire. Après un certain temps, j'ai réalisé que je pouvais simplement faire faire le travail à Node:
la source
instanceof
et noninstanceOf
.