它是不可能的字符串化透过JSON.stringify错误?它是不可能的字符串化透过JSON.stri

2019-05-08 18:25发布

重现问题

我试图绕过使用网络套接字错误消息,当运行到一个问题。 我可以复制我使用所面临的问题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给了我同样的结果,而有趣的是,火狐至少做出尝试,但留下了消息:

>>> 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 ? 如果不是,为什么会发生这种行为的发生?

解决这个获得方法

  • 用简单的基于字符串的错误消息的坚持,也可以创建个人的错误对象,不依赖本机错误对象。
  • 拉性能: JSON.stringify({ message: error.message, stack: error.stack })

更新

@Ray特里建议中,我看看的评论属性描述 。 很显然,现在为什么它不工作:

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

接受的答案提供了此问题的方法。

Answer 1:

您可以定义一个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()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));


Answer 2:

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

似乎工作

[ 由/ U / ub3rgeek上/ R / JavaScript的评论 ]以下felixfbecker的评论



Answer 3:

修改乔纳森的伟大的答案,以免猴子修补:

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'));


Answer 4:

由于没有人在谈论为什么的一部分,我会回答这些

问:有没有办法跟JSON.stringify到字符串化机错误消息?

没有。

问:如果没有,为什么会发生这种行为的发生?

从文档JSON.stringify() ,

对于其他所有的对象实例(包括地图,设置,WeakMap和WeakSet),只有他们的枚举的属性将被序列化。

Error的对象不具有其枚举的属性,这就是为什么它打印一个空对象。



Answer 5:

有一个伟大的Node.js包为: serialize-error

它处理好,甚至嵌套错误的对象,我其实我需要多少在我的项目。

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



Answer 6:

你也可以重新定义那些非枚举的属性是可枚举。

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

也许stack财产了。



Answer 7:

答案都不上面似乎正确序列化这些都对错误的原型属性(因为getOwnPropertyNames()不包括继承的属性)。 我也没能像重新定义建议的答案之一的属性。

这是我想出了一个解决方案 - 它使用lodash但你可以使用这些功能的通用版本替换lodash。

 function recursivePropertyFinder(obj){
    if( obj === Object.prototype){
        return {};
    }else{
        return _.reduce(Object.getOwnPropertyNames(obj), 
            function copy(result, value, key) {
                if( !_.isFunction(obj[value])){
                    if( _.isObject(obj[value])){
                        result[value] = recursivePropertyFinder(obj[value]);
                    }else{
                        result[value] = obj[value];
                    }
                }
                return result;
            }, recursivePropertyFinder(Object.getPrototypeOf(obj)));
    }
}


Error.prototype.toJSON = function(){
    return recursivePropertyFinder(this);
}

下面是测试我在Chrome中所做的:

var myError = Error('hello');
myError.causedBy = Error('error2');
myError.causedBy.causedBy = Error('error3');
myError.causedBy.causedBy.displayed = true;
JSON.stringify(myError);

{"name":"Error","message":"hello","stack":"Error: hello\n    at <anonymous>:66:15","causedBy":{"name":"Error","message":"error2","stack":"Error: error2\n    at <anonymous>:67:20","causedBy":{"name":"Error","message":"error3","stack":"Error: error3\n    at <anonymous>:68:29","displayed":true}}}  


Answer 8:

我们需要连载任意对象分层结构,其中,所述根或任何分层结构中的嵌套属性的可能是错误的实例。

我们的解决方案是使用replacer的PARAM 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)) 



文章来源: Is it not possible to stringify an Error using JSON.stringify?