Воспроизведение проблемы
Я столкнулся с проблемой при попытке передать сообщения об ошибках с помощью веб-сокетов. Я могу повторить проблему, с которой сталкиваюсь, JSON.stringify
чтобы удовлетворить более широкую аудиторию:
// 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);
'{}'
Проблема в том, что я получаю пустой объект.
Что я пробовал
Браузеры
Сначала я попытался покинуть node.js и запустить его в разных браузерах. Chrome версии 28 дает мне тот же результат, и, что интересно, Firefox по крайней мере делает попытку, но пропускает сообщение:
>>> JSON.stringify(error); // Firebug, Firefox 23
{"fileName":"debug eval code","lineNumber":1,"stack":"@debug eval code:1\n"}
Функция заменителя
Затем я посмотрел на Error.prototype . Это показывает, что прототип содержит такие методы, как toString и toSource . Зная, что функции не могут быть строковыми, я включил функцию- заменитель при вызове JSON.stringify, чтобы удалить все функции, но затем понял, что у него тоже странное поведение:
var error = new Error('simple error message');
JSON.stringify(error, function(key, value) {
console.log(key === ''); // true (?)
console.log(value === error); // true (?)
});
Кажется, он не зацикливается на объекте, как обычно, и поэтому я не могу проверить, является ли ключ функцией, и игнорировать его.
Вопрос
Есть ли способ привести в порядок собственные сообщения об ошибках JSON.stringify
? Если нет, то почему это происходит?
Методы обойти это
- Придерживайтесь простых сообщений об ошибках на основе строк или создавайте личные объекты ошибок и не полагайтесь на собственный объект Error.
- Тянуть свойства:
JSON.stringify({ message: error.message, stack: error.stack })
Обновления
@Ray Toal Предложено в комментарии, что я смотрю на дескрипторы свойств . Теперь понятно, почему это не работает:
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);
}
Вывод:
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 }
Ключ: enumerable: false
.
Принятый ответ обеспечивает обходной путь для этой проблемы.
источник
Ответы:
Вы можете определить
Error.prototype.toJSON
для получения простой,Object
представляющейError
:Использование
Object.defineProperty()
добавляет,toJSON
не будучиenumerable
самим свойством.Что касается модификации
Error.prototype
, хотя онаtoJSON()
не может быть определена специально дляError
s, метод все еще стандартизирован для объектов в целом (см. Шаг 3). Таким образом, риск столкновений или конфликтов минимален.Хотя, по - прежнему избегать его полностью,
JSON.stringify()
«sreplacer
параметр может быть использован вместо:источник
.getOwnPropertyNames()
вместо.keys()
, вы получите неперечислимые свойства без необходимости определять их вручную.key
in,function replaceErrors(key, value)
чтобы избежать конфликта имен с.forEach(function (key) { .. })
;replaceErrors
key
параметр не используется в этом ответе.key
в этом примере, хотя и разрешено, потенциально сбивает с толку, поскольку оставляет сомнение в том, намеревался ли автор ссылаться на внешнюю переменную или нет.propName
будет более выразительным выбором для внутреннего цикла. (Кстати, я думаю, что @ 404NotFound означало «линтер» (инструмент статического анализа), а не «компоновщик» ). В любом случае, использование пользовательскойreplacer
функции является отличным решением для этой проблемы, поскольку она решает проблему в одном подходящем месте и не меняет нативную функцию. / глобальное поведение.похоже на работу
[ из комментария / u / ub3rgeek к / r / javascript ] и комментария felixfbecker ниже
источник
JSON.stringify(err, Object.getOwnPropertyNames(err))
ValidationError
типов. Это не приведёт в порядок вложенныйerrors
объект в объект ошибки типа MongooseValidationError
.var spam = { a: 1, b: { b: 2, b2: 3} };
и работаетObject.getOwnPropertyNames(spam)
, вы получите["a", "b"]
- обманчиво здесь, потому чтоb
объект имеет свой собственныйb
. Вы получите оба в своем звонке, но вы пропуститеspam.b.b2
. Это плохо.message
иstack
включены в JSON.Поскольку никто не говорит о части « почему» , я отвечу на нее.
Почему это
JSON.stringify
возвращает пустой объект?Ответ
Из документа JSON.stringify () ,
и
Error
объект не имеет своих перечисляемых свойств, поэтому он печатает пустой объект.источник
JSON.stringify
егоreplacer
параметр.Изменение отличного ответа Джонатана, чтобы избежать исправлений обезьяны:
источник
monkey patching
:)toJSON
, непосредственноError
прототип «S , который часто не хорошая идея. Может быть , кто - то уже есть, которых это проверяет, но вы не знаете , что что делает другая версия. Или, если кто-то неожиданно получит вашу или предположит, что прототип Error обладает особыми свойствами, все может испортиться.)Существует большой пакет Node.js для этого:
serialize-error
.Он хорошо обрабатывает даже вложенные объекты Error, что мне действительно нужно в моем проекте.
https://www.npmjs.com/package/serialize-error
источник
Вы также можете просто переопределить эти не перечисляемые свойства, чтобы они были перечисляемыми.
и, возможно,
stack
собственность тоже.источник
Нам нужно было сериализовать произвольную иерархию объектов, где корень или любое из вложенных свойств в иерархии могут быть экземплярами Error.
Нашим решением было использовать
replacer
параметрJSON.stringify()
, например:источник
Похоже, что ни один из приведенных выше ответов не мог правильно сериализовать свойства, относящиеся к прототипу Error (поскольку
getOwnPropertyNames()
он не включает унаследованные свойства). Я также не смог переопределить свойства, как один из предложенных ответов.Это решение, которое я придумал, - оно использует lodash, но вы можете заменить lodash на общие версии этих функций.
Вот тест, который я сделал в Chrome:
источник
Я работал над форматом JSON для добавителей журналов и в итоге попытался решить аналогичную проблему. Через некоторое время я понял, что могу просто заставить Node делать работу:
источник
instanceof
и нетinstanceOf
.