Odtwarzanie problemu
Występuje problem podczas próby przekazywania komunikatów o błędach przy użyciu gniazd sieciowych. Mogę powtórzyć problem, z którym się spotykam, JSON.stringify
aby dotrzeć do szerszego grona odbiorców:
// 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);
'{}'
Problem polega na tym, że kończę na pustym obiekcie.
Co próbowałem
Przeglądarki
Najpierw próbowałem opuścić node.js i uruchomić go w różnych przeglądarkach. Wersja Chrome 28 daje mi ten sam wynik i co ciekawe, Firefox przynajmniej próbuje, ale pomija komunikat:
>>> JSON.stringify(error); // Firebug, Firefox 23
{"fileName":"debug eval code","lineNumber":1,"stack":"@debug eval code:1\n"}
Funkcja zamiennika
Następnie spojrzałem na prototyp Error.prototype . Pokazuje, że prototyp zawiera metody takie jak toString i toSource . Wiedząc, że funkcji nie można sprecyzować, do wywołania JSON.stringify zawarłem funkcję zamiennika, aby usunąć wszystkie funkcje, ale potem zdałem sobie sprawę, że również zachowuje się dziwnie:
var error = new Error('simple error message');
JSON.stringify(error, function(key, value) {
console.log(key === ''); // true (?)
console.log(value === error); // true (?)
});
Wydaje się, że nie zapętla obiektu, jak zwykle, dlatego nie mogę sprawdzić, czy klucz jest funkcją i go zignorować.
Pytanie
Czy jest jakiś sposób na nawiasowanie natywnych komunikatów o błędach JSON.stringify
? Jeśli nie, dlaczego tak się dzieje?
Metody obejścia tego
- Trzymaj się prostych komunikatów o błędach opartych na łańcuchach lub twórz osobiste obiekty błędów i nie polegaj na rodzimym obiekcie Error.
- Właściwości ciągnięcia:
JSON.stringify({ message: error.message, stack: error.stack })
Aktualizacje
@Ray Toal Sugerowane w komentarzu, że patrzę na deskryptory właściwości . Teraz jest jasne, dlaczego to nie działa:
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);
}
Wynik:
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 }
Klucz: enumerable: false
.
Zaakceptowana odpowiedź stanowi obejście tego problemu.
źródło
Odpowiedzi:
Możesz zdefiniować a,
Error.prototype.toJSON
aby pobrać równinęObject
reprezentującąError
:Używanie
Object.defineProperty()
dodaje,toJSON
aleenumerable
sama nie jest własnością.Jeśli chodzi o modyfikację
Error.prototype
, chociażtoJSON()
nie można jej zdefiniowaćError
konkretnie, metoda jest nadal standaryzowana dla obiektów w ogóle (patrz: krok 3). Zatem ryzyko kolizji lub konfliktów jest minimalne.Choć nadal go całkowicie uniknąć,
JSON.stringify()
jestreplacer
parametr może być stosowany zamiast:źródło
.getOwnPropertyNames()
zamiast.keys()
, otrzymasz właściwości niepoliczalne, bez konieczności ich ręcznego definiowania.key
in,function replaceErrors(key, value)
aby uniknąć konfliktu nazw.forEach(function (key) { .. })
;replaceErrors
key
parametr jest używany w tej odpowiedzi.key
w tym przykładzie, choć dozwolone, jest potencjalnie mylące, ponieważ pozostawia wątpliwości, czy autor zamierzał odwoływać się do zmiennej zewnętrznej, czy nie.propName
byłby bardziej wyrazistym wyborem dla wewnętrznej pętli. (BTW, myślę, że @ 404NotFound oznaczało „ linter ” (narzędzie do analizy statycznej), a nie „linker” ) W każdym razie użyciereplacer
funkcji niestandardowej jest doskonałym rozwiązaniem, ponieważ rozwiązuje problem w jednym, odpowiednim miejscu i nie zmienia natywnego / globalne zachowanie.wydaje się działać
[ z komentarza / u / ub3rgeek do / r / javascript ] i komentarza felixfbecker poniżej
źródło
JSON.stringify(err, Object.getOwnPropertyNames(err))
ValidationError
typów. Nie spowoduje to strunowania zagnieżdżonegoerrors
obiektu w obiekcie typu błąd MongooseValidationError
.var spam = { a: 1, b: { b: 2, b2: 3} };
i biegnieszObject.getOwnPropertyNames(spam)
, dostaniesz["a", "b"]
- oszukańcze, ponieważb
obiekt ma swój własnyb
. Można dostać zarówno w stringify rozmowy, ale chcesz przegapićspam.b.b2
. To źle.message
istack
są zawarte w JSON.Ponieważ nikt nie mówi o części dlaczego , odpowiem na to pytanie.
Dlaczego
JSON.stringify
zwraca pusty obiekt?Odpowiedź
Z dokumentu JSON.stringify () ,
a
Error
obiekt nie ma swoich wyliczalnych właściwości, dlatego drukuje pusty obiekt.źródło
JSON.stringify
przy użyciu jegoreplacer
parametru.Modyfikacja świetnej odpowiedzi Jonathana, aby uniknąć łatania małp:
źródło
monkey patching
:)toJSON
, bezpośrednio doError
„s prototypu , który często nie jest to świetny pomysł. Może ktoś ma inny już, która w tym czeki, ale wtedy nie wiem co tak jak robi to inna wersja. Lub jeśli ktoś niespodziewanie dostanie twoją lub przyjmie, że prototyp Error ma określone właściwości, wszystko może się popsuć.)Jest to świetny pakiet dla node.js, że:
serialize-error
.Dobrze radzi sobie nawet z zagnieżdżonymi obiektami Error, czego tak naprawdę potrzebowałem w swoim projekcie.
https://www.npmjs.com/package/serialize-error
źródło
Możesz także przedefiniować te właściwości, których nie można wyliczyć, aby były wyliczalne.
a może
stack
też nieruchomości.źródło
Musieliśmy serializować dowolną hierarchię obiektów, w której pierwiastek główny lub dowolna z zagnieżdżonych właściwości w hierarchii może być wystąpieniem błędu.
Nasze rozwiązanie było użyć
replacer
param sięJSON.stringify()
, np:źródło
Żadna z powyższych odpowiedzi nie wydawała się poprawnie serializować właściwości, które znajdują się w prototypie błędu (ponieważ
getOwnPropertyNames()
nie obejmuje właściwości dziedziczonych). Nie byłem również w stanie przedefiniować właściwości, tak jak w jednej z sugerowanych odpowiedzi.Oto rozwiązanie, które wymyśliłem - używa lodash, ale można go zastąpić ogólnymi wersjami tych funkcji.
Oto test, który zrobiłem w Chrome:
źródło
Pracowałem nad formatem JSON dla programów dołączających dzienniki i skończyłem tutaj, próbując rozwiązać podobny problem. Po chwili zdałem sobie sprawę, że mogę po prostu zmusić Node do wykonania pracy:
źródło
instanceof
i nieinstanceOf
.