Das Problem reproduzieren
Beim Versuch, Fehlermeldungen mithilfe von Web-Sockets weiterzugeben, tritt ein Problem auf. Ich kann das Problem, mit dem ich konfrontiert bin JSON.stringify
, wiederholen, um ein breiteres Publikum anzusprechen:
// 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);
'{}'
Das Problem ist, dass ich am Ende ein leeres Objekt habe.
Was ich versucht habe
Browser
Ich habe zuerst versucht, node.js zu verlassen und es in verschiedenen Browsern auszuführen. Die Chrome-Version 28 liefert das gleiche Ergebnis, und interessanterweise unternimmt Firefox zumindest einen Versuch, lässt jedoch die folgende Meldung aus:
>>> JSON.stringify(error); // Firebug, Firefox 23
{"fileName":"debug eval code","lineNumber":1,"stack":"@debug eval code:1\n"}
Ersatzfunktion
Ich habe mir dann den Error.prototype angesehen . Es zeigt, dass der Prototyp Methoden wie toString und toSource enthält . Da ich wusste, dass Funktionen nicht stringifiziert werden können, habe ich beim Aufrufen von JSON.stringify eine Ersetzungsfunktion eingefügt, um alle Funktionen zu entfernen, aber dann festgestellt, dass auch diese ein seltsames Verhalten aufweist:
var error = new Error('simple error message');
JSON.stringify(error, function(key, value) {
console.log(key === ''); // true (?)
console.log(value === error); // true (?)
});
Es scheint das Objekt nicht wie gewohnt zu durchlaufen, und daher kann ich nicht überprüfen, ob die Taste eine Funktion ist, und sie ignorieren.
Die Frage
Gibt es eine Möglichkeit, native Fehlermeldungen mit zu kennzeichnen JSON.stringify
? Wenn nicht, warum tritt dieses Verhalten auf?
Methoden, um dies zu umgehen
- Halten Sie sich an einfache stringbasierte Fehlermeldungen oder erstellen Sie persönliche Fehlerobjekte und verlassen Sie sich nicht auf das native Fehlerobjekt.
- Pull-Eigenschaften:
JSON.stringify({ message: error.message, stack: error.stack })
Aktualisierung
@ Ray Toal In einem Kommentar vorgeschlagen, dass ich mir die Eigenschaftsbeschreibungen anschaue . Es ist jetzt klar, warum es nicht funktioniert:
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);
}
Ausgabe:
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 }
Schlüssel : enumerable: false
.
Die akzeptierte Antwort bietet eine Problemumgehung für dieses Problem.
quelle
Antworten:
Sie können a definieren
Error.prototype.toJSON
, um eine Ebene abzurufen, die FolgendesObject
darstelltError
:Verwenden von
Object.defineProperty()
Adds,toJSON
ohne dass es sich um eineenumerable
Eigenschaft handelt.In Bezug auf das Modifizieren
Error.prototype
ist die Methode , obwohl sietoJSON()
möglicherweise nichtError
speziell für s definiert ist, für Objekte im Allgemeinen standardisiert (siehe Schritt 3). Das Risiko von Kollisionen oder Konflikten ist also minimal.Obwohl, noch sie vollständig zu vermeiden,
JSON.stringify()
‚s -replacer
Parameter können stattdessen verwendet werden:quelle
.getOwnPropertyNames()
anstelle von verwenden.keys()
, erhalten Sie die nicht aufzählbaren Eigenschaften, ohne sie manuell definieren zu müssen.key
in wählenfunction replaceErrors(key, value)
, um Namenskonflikte mit zu vermeiden.forEach(function (key) { .. })
. DerreplaceErrors
key
Parameter wird in dieser Antwort nicht verwendet.key
in diesem Beispiel ist zwar zulässig, aber möglicherweise verwirrend, da Zweifel daran bestehen, ob der Autor beabsichtigte, auf die äußere Variable zu verweisen oder nicht.propName
wäre eine ausdrucksstärkere Wahl für die innere Schleife. (Übrigens, ich denke, @ 404NotFound bedeutete "linter" (statisches Analysetool), nicht "Linker". ) In jedem Fall ist die Verwendung einer benutzerdefiniertenreplacer
Funktion eine hervorragende Lösung dafür, da das Problem an einem geeigneten Ort gelöst wird und sich nicht ändert / globales Verhalten.scheint zu funktionieren
[ aus einem Kommentar von / u / ub3rgeek zu / r / javascript ] und dem Kommentar von felixfbecker unten
quelle
JSON.stringify(err, Object.getOwnPropertyNames(err))
ValidationError
Typen. Dadurch wird das verschachtelteerrors
Objekt in einem Mongoose- Fehlerobjekt vom Typ nicht stringifiziertValidationError
.var spam = { a: 1, b: { b: 2, b2: 3} };
und laufenObject.getOwnPropertyNames(spam)
, werden Sie["a", "b"]
hier täuschen, weil dasb
Objekt sein eigenes hatb
. Sie würden beide in Ihrem Stringify-Anruf erhalten, aber Sie würden vermissenspam.b.b2
. Das ist schlecht.message
undstack
sind in der JSON enthalten.Da niemand über das Warum spricht , werde ich darauf antworten.
Warum gibt dies
JSON.stringify
ein leeres Objekt zurück?Antworten
Aus dem Dokument von JSON.stringify () ,
und
Error
Objekt hat nicht seine aufzählbaren Eigenschaften, deshalb druckt es ein leeres Objekt.quelle
JSON.stringify
denreplacer
Parameter zu verwenden.Ändern Sie Jonathans großartige Antwort, um das Patchen von Affen zu vermeiden:
quelle
monkey patching
:)toJSON
, direkt aufError
‚s - Prototyp , die oft keine gute Idee. Vielleicht hat jemand anderes schon hat, der diese Kontrollen, aber dann wissen Sie nicht , was diese andere Version tut es. Oder wenn jemand unerwartet Ihre bekommt oder annimmt, dass der Prototyp von Error bestimmte Eigenschaften hat, könnten die Dinge schief gehen.)Dafür gibt es ein großartiges Node.js-Paket :
serialize-error
.Es verarbeitet auch verschachtelte Fehlerobjekte gut, was ich eigentlich in meinem Projekt sehr gebraucht habe.
https://www.npmjs.com/package/serialize-error
quelle
Sie können diese nicht aufzählbaren Eigenschaften auch einfach neu definieren, damit sie aufzählbar sind.
und vielleicht auch
stack
Eigentum.quelle
Wir mussten eine beliebige Objekthierarchie serialisieren, wobei die Wurzel oder eine der verschachtelten Eigenschaften in der Hierarchie Fehlerinstanzen sein könnten.
Unsere Lösung bestand darin, den
replacer
Parameter zu verwendenJSON.stringify()
, z.quelle
Keine der obigen Antworten schien Eigenschaften, die sich auf dem Prototyp des Fehlers befinden, ordnungsgemäß zu serialisieren (da
getOwnPropertyNames()
ererbte Eigenschaften nicht enthält). Ich war auch nicht in der Lage, die Eigenschaften wie in einer der vorgeschlagenen Antworten neu zu definieren.Dies ist die Lösung, die ich mir ausgedacht habe - sie verwendet lodash, aber Sie könnten lodash durch generische Versionen dieser Funktionen ersetzen.
Hier ist der Test, den ich in Chrome durchgeführt habe:
quelle
Ich habe an einem JSON-Format für Protokoll-Appender gearbeitet und bin hier gelandet, um ein ähnliches Problem zu lösen. Nach einer Weile wurde mir klar, dass ich Node einfach dazu bringen konnte, die Arbeit zu erledigen:
quelle
instanceof
und nichtinstanceOf
.