[javascript] JSON.stringify를 사용하여 오류를 문자열화할 수 없습니까?

문제 재현

웹 소켓 사용과 관련된 오류 메시지를 전달하려고 할 때 문제가 발생했습니다. 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 을 살펴 보았습니다 . 프로토 타입에 toStringtoSource 와 같은 메소드가 포함되어 있음을 보여줍니다 . 함수를 문자열 화 할 수 없다는 것을 알고 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 })

업데이트

@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.toJSONObject나타내는 일반을 검색 할 수 있습니다 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()replacer매개 변수를 사용할 수 있습니다.

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

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

        return error;
    }

    return value;
}

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

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


답변

JSON.stringify(err, Object.getOwnPropertyNames(err))

작동하는 것 같습니다

[ / r / javascript에 대한 / u / ub3rgeek의 의견] 및 felixfbecker의 의견


답변

아무도 이유 에 대해 이야기하지 않기 때문에 부분 대답하겠습니다.

왜 이것이 JSON.stringify빈 객체를 반환합니까?

> JSON.stringify(error);
'{}'

대답

JSON.stringify () 문서 에서

다른 모든 Object 인스턴스 (Map, Set, WeakMap 및 WeakSet 포함)의 경우 열거 가능한 속성 만 직렬화됩니다.

그리고 Error객체는 빈 객체를 인쇄 그 이유는, 그 열거 속성이 없습니다.


답변

원숭이 패치를 피하기 위해 Jonathan의 훌륭한 답변 수정 :

var stringifyError = function(err, filter, space) {
  var plainObject = {};
  Object.getOwnPropertyNames(err).forEach(function(key) {
    plainObject[key] = err[key];
  });
  return JSON.stringify(plainObject, filter, space);
};

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

console.log(stringifyError(error, null, '\t'));


답변

이를위한 훌륭한 Node.js 패키지가 있습니다 : serialize-error .

내 프로젝트에서 실제로 필요한 중첩 된 Error 객체도 잘 처리합니다.

https://www.npmjs.com/package/serialize-error


답변

열거 불가능한 속성을 열거 가능하도록 재정의 할 수도 있습니다.

Object.defineProperty(Error.prototype, 'message', {
    configurable: true,
    enumerable: true
});

그리고 아마도 stack재산.


답변

계층의 루트 또는 중첩 속성이 오류 인스턴스 일 수있는 임의의 개체 계층을 직렬화해야했습니다.

우리의 솔루션은 다음과 같은 replacer매개 변수 를 사용하는 것 입니다 JSON.stringify().

function jsonFriendlyErrorReplacer(key, value) {
  if (value instanceof Error) {
    return {
      // Pull all enumerable properties, supporting properties on custom Errors
      ...value,
      // Explicitly pull Error's non-enumerable properties
      name: value.name,
      message: value.message,
      stack: value.stack,
    }
  }

  return value
}

let obj = {
    error: new Error('nested error message')
}

console.log('Result WITHOUT custom replacer:', JSON.stringify(obj))
console.log('Result WITH custom replacer:', JSON.stringify(obj, jsonFriendlyErrorReplacer))