Mereproduksi masalah
Saya mengalami masalah ketika mencoba menyampaikan pesan kesalahan menggunakan soket web. Saya dapat meniru masalah yang saya hadapi JSON.stringify
untuk memenuhi audiensi yang lebih luas:
// 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);
'{}'
Masalahnya adalah bahwa saya berakhir dengan objek kosong.
Apa yang saya coba
Browser
Saya pertama kali mencoba meninggalkan node.js dan menjalankannya di berbagai browser. Chrome versi 28 memberi saya hasil yang sama, dan cukup menarik, Firefox setidaknya membuat upaya tetapi tidak menerima pesan:
>>> JSON.stringify(error); // Firebug, Firefox 23
{"fileName":"debug eval code","lineNumber":1,"stack":"@debug eval code:1\n"}
Fungsi replacer
Saya kemudian melihat Error.prototype . Ini menunjukkan bahwa prototipe berisi metode seperti toString dan toSource . Mengetahui bahwa fungsi tidak dapat diubah, saya menyertakan fungsi replacer saat memanggil JSON.stringify untuk menghapus semua fungsi, tetapi kemudian menyadari bahwa itu juga memiliki beberapa perilaku aneh:
var error = new Error('simple error message');
JSON.stringify(error, function(key, value) {
console.log(key === ''); // true (?)
console.log(value === error); // true (?)
});
Tampaknya tidak untuk mengulang objek seperti biasanya, dan karena itu saya tidak dapat memeriksa apakah kuncinya adalah fungsi dan mengabaikannya.
Pertanyaan
Apakah ada cara untuk merangkai pesan kesalahan asli dengan JSON.stringify
? Jika tidak, mengapa perilaku ini terjadi?
Metode untuk mengatasi ini
- Tetap dengan pesan kesalahan sederhana berbasis string, atau buat objek kesalahan pribadi dan jangan mengandalkan objek kesalahan asli.
- Properti tarik:
JSON.stringify({ message: error.message, stack: error.stack })
Pembaruan
@ Ray Toal Diusulkan dalam komentar yang saya lihat di deskriptor properti . Jelas sekarang mengapa itu tidak berhasil:
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);
}
Keluaran:
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
.
Jawaban yang diterima memberikan solusi untuk masalah ini.
sumber
Jawaban:
Anda dapat menentukan a
Error.prototype.toJSON
untuk mengambil suatu dataran yangObject
mewakiliError
:Menggunakan
Object.defineProperty()
tambahtoJSON
tanpa menjadienumerable
properti itu sendiri.Mengenai memodifikasi
Error.prototype
, sementaratoJSON()
mungkin tidak didefinisikan untukError
s secara khusus, metode ini masih standar untuk objek secara umum (ref: langkah 3). Jadi, risiko tabrakan atau konflik minimal.Meskipun, masih menghindarinya sepenuhnya,
JSON.stringify()
'sreplacer
parameter dapat digunakan sebagai pengganti:sumber
.getOwnPropertyNames()
alih-alih.keys()
, Anda akan mendapatkan properti yang tidak dapat dihitung tanpa harus mendefinisikannya secara manual.key
difunction replaceErrors(key, value)
untuk menghindari penamaan konflik dengan.forEach(function (key) { .. })
; yangreplaceErrors
key
parameter yang tidak terpakai dalam jawaban ini.key
dalam contoh ini, sementara diizinkan, berpotensi membingungkan karena meninggalkan keraguan apakah penulis bermaksud merujuk ke variabel luar atau tidak.propName
akan menjadi pilihan yang lebih ekspresif untuk loop dalam. (BTW, saya pikir @ 404NotFound berarti "linter" (alat analisis statis) bukan "linker" ). Bagaimanapun, menggunakanreplacer
fungsi kustom adalah solusi yang sangat baik untuk ini karena ini memecahkan masalah dalam satu, tempat yang tepat dan tidak mengubah asli / Perilaku global.sepertinya berhasil
[ dari komentar oleh / u / ub3rgeek di / r / javascript ] dan komentar felixfbecker di bawah ini
sumber
JSON.stringify(err, Object.getOwnPropertyNames(err))
ValidationError
jenis. Ini tidak akan mengikaterrors
objek bersarang di objek tipe kesalahan luwakValidationError
.var spam = { a: 1, b: { b: 2, b2: 3} };
dan menjalankanObject.getOwnPropertyNames(spam)
, Anda akan mendapatkan["a", "b"]
- menipu di sini, karenab
objek memiliki itu sendirib
. Anda akan mendapatkan keduanya dalam panggilan tegar, tetapi Anda akan kehilanganspam.b.b2
. Itu buruk.message
danstack
termasuk dalam JSON.Karena tidak ada yang berbicara tentang bagian mengapa , aku akan menjawabnya.
Mengapa ini
JSON.stringify
mengembalikan objek kosong?Menjawab
Dari dokumen JSON.stringify () ,
dan
Error
objek tidak memiliki properti enumerable, itu sebabnya ia mencetak objek kosong.sumber
JSON.stringify
menggunakanreplacer
parameternya.Memodifikasi jawaban hebat Jonathan untuk menghindari tambalan monyet:
sumber
monkey patching
:)toJSON
,, langsung keError
prototipe , yang seringkali bukan ide bagus. Mungkin sudah ada orang lain, yang memeriksa ini, tetapi kemudian Anda tidak tahu apa yang versi lain lakukan. Atau jika seseorang secara tak terduga mendapatkan milik Anda, atau menganggap prototipe Error memiliki sifat tertentu, hal-hal bisa bork.)Ada paket Node.js besar untuk itu:
serialize-error
.Ini menangani dengan baik bahkan objek Kesalahan bersarang, apa yang sebenarnya saya butuhkan dalam proyek saya.
https://www.npmjs.com/package/serialize-error
sumber
Anda juga bisa mendefinisikan ulang properti yang tidak dapat dihitung menjadi yang dapat dihitung.
dan mungkin
stack
properti juga.sumber
Kami harus membuat serial hierarki objek yang sewenang-wenang, di mana root atau salah satu properti yang bersarang dalam hierarki dapat menjadi instance dari Kesalahan.
Solusi kami adalah menggunakan
replacer
paramJSON.stringify()
, misalnya:sumber
Tak satu pun dari jawaban di atas yang tampaknya membuat cerita bersambung properti dengan benar yang ada pada prototipe Kesalahan (karena
getOwnPropertyNames()
tidak menyertakan properti yang diwarisi). Saya juga tidak dapat mendefinisikan ulang properti seperti salah satu jawaban yang disarankan.Ini adalah solusi yang saya buat - menggunakan lodash tetapi Anda dapat mengganti lodash dengan versi generik dari fungsi-fungsi tersebut.
Inilah tes yang saya lakukan di Chrome:
sumber
Saya sedang mengerjakan format JSON untuk appenders log dan berakhir di sini mencoba untuk memecahkan masalah yang sama. Setelah beberapa saat, saya menyadari bahwa saya hanya bisa membuat Node melakukan pekerjaan:
sumber
instanceof
dan tidakinstanceOf
.