1. ホーム
  2. javascript

[解決済み] JSON.stringifyでErrorを文字列化することはできないのでしょうか?

2022-03-21 16:34:03

質問

問題の再現

ウェブソケットを使用してエラーメッセージを渡そうとすると、ある問題にぶつかるんだ。私が直面している問題は、以下の方法で再現できます。 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 . このプロトタイプには、次のようなメソッドが含まれていることがわかります。 文字列 ソース . 関数が文字列化できないことを知っていたので、私はこの関数に 置き換え機能 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 ? そうでない場合、なぜこのような動作が発生するのでしょうか?

回避するための方法

  • シンプルな文字列ベースのエラーメッセージにこだわるか、個人用のエラーオブジェクトを作成し、ネイティブのエラーオブジェクトに依存しないようにします。
  • プロパティを引っ張る。 JSON.stringify({ message: error.message, stack: error.stack })

更新情報

レイ・トール コメントで提案されたので、見てみると プロパティ記述子 . なぜうまくいかないのか、理由が明らかになりました。

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 .

Accepted answer は、この問題の回避策を提供します。

解決方法を教えてください。

を定義することができます。 Error.prototype.toJSON を取得するために、プレーンな Object を表します。 Error :

if (!('toJSON' in Error.prototype))
Object.defineProperty(Error.prototype, 'toJSON', {
    value: function () {
        var alt = {};

        Object.getOwnPropertyNames(this).forEach(function (key) {
            alt[key] = this[key];
        }, this);

        return alt;
    },
    configurable: true,
    writable: true
});

var error = new Error('testing');
error.detail = 'foo bar';

console.log(JSON.stringify(error));
// {"message":"testing","detail":"foo bar"}

使用方法 Object.defineProperty() が追加されます。 toJSON でなくとも enumerable プロパティそのものです。


の修正について Error.prototype 一方 toJSON() には定義されないかもしれません。 Error を具体的に説明する。 その方法はまだ標準化されていません。 は、一般的なオブジェクトのためのものです(参照:ステップ3)。そのため、衝突や競合のリスクは最小限に抑えられます。

それでも、完全に避けるためには JSON.stringify() 's replacer パラメータ を代わりに使用することができます。

function replaceErrors(key, value) {
    if (value instanceof Error) {
        var error = {};

        Object.getOwnPropertyNames(value).forEach(function (propName) {
            error[propName] = value[propName];
        });

        return error;
    }

    return value;
}

var error = new Error('testing');
error.detail = 'foo bar';

console.log(JSON.stringify(error, replaceErrors));