Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 无法使用JSON.stringify字符串化错误吗? 重现问题_Javascript_Json_Node.js_Error Handling - Fatal编程技术网

Javascript 无法使用JSON.stringify字符串化错误吗? 重现问题

Javascript 无法使用JSON.stringify字符串化错误吗? 重现问题,javascript,json,node.js,error-handling,Javascript,Json,Node.js,Error Handling,我在尝试使用web套接字传递错误消息时遇到了一个问题。我可以使用JSON.stringify复制我面临的问题,以迎合更广泛的受众: //节点v0.10.15 >var error=新错误(“简单错误消息”); 未定义 >错误 [错误:简单错误消息] >getOwnPropertyNames(错误); [‘堆栈’、‘参数’、‘类型’、‘消息’] >stringify(错误); '{}' 问题是我最终得到的是一个空对象 我试过的 浏览器 我首先尝试离开node.js并在各种浏览器中运行它。Chro

我在尝试使用web套接字传递错误消息时遇到了一个问题。我可以使用
JSON.stringify
复制我面临的问题,以迎合更广泛的受众:

//节点v0.10.15
>var error=新错误(“简单错误消息”);
未定义
>错误
[错误:简单错误消息]
>getOwnPropertyNames(错误);
[‘堆栈’、‘参数’、‘类型’、‘消息’]
>stringify(错误);
'{}'
问题是我最终得到的是一个空对象

我试过的 浏览器

我首先尝试离开node.js并在各种浏览器中运行它。Chrome版本28给了我同样的结果,有趣的是,Firefox至少做了一次尝试,但忽略了以下信息:

>JSON.stringify(错误);//Firebug,Firefox 23
{“文件名”:“调试评估代码”,“行号”:1,“堆栈”:“@debug eval code:1\n”}
替换功能

然后我看了看照片。它表明原型包含了和等方法。知道函数不能字符串化,我在调用JSON.stringify删除所有函数时加入了一个,但后来意识到它也有一些奇怪的行为:

var error=新错误(“简单错误消息”);
stringify(错误,函数(键,值){
console.log(key=='');//true(?)
console.log(值==错误);//真(?)
});
它似乎不像通常那样在对象上循环,因此我无法检查键是否是函数并忽略它

问题 有没有办法用
JSON.stringify
字符串化本机错误消息?如果没有,为什么会发生这种行为

绕开这个问题的方法
  • 坚持使用简单的基于字符串的错误消息,或者创建个人错误对象,不要依赖本机错误对象
  • 拉取属性:
    JSON.stringify({message:error.message,stack:error.stack})
更新 在评论中建议我看一看。现在很清楚为什么它不起作用:

var error=新错误(“简单错误消息”);
var propertyNames=Object.getOwnPropertyNames(错误);
var描述符;
对于(变量属性,i=0,len=propertyNames.length;i
输出:

stack{get:[函数],
set:[函数],
可枚举:false,
可配置:true}
参数{值:未定义,
可写:对,
可枚举:false,
可配置:true}
类型{值:未定义,
可写:对,
可枚举:false,
可配置:true}
消息{value:'简单错误消息',
可写:对,
可枚举:false,
可配置:true}
键:
可枚举:false


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

您可以定义
Error.prototype.toJSON
来检索表示
错误的普通
对象:

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
});
使用将
添加到JSON
,而不将其本身作为
可枚举的
属性


关于修改
Error.prototype
,而
toJSON()
可能不会被定义为
Error
s,特别是一般对象(参考:步骤3)。因此,碰撞或冲突的风险最小

但是,为了完全避免,可以使用以下方法:

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

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

您还可以将那些不可枚举的属性重新定义为可枚举的

Object.defineProperty(Error.prototype, 'message', {
    configurable: true,
    enumerable: true
});
也可能是
stack
属性

JSON.stringify(err, Object.getOwnPropertyNames(err))
似乎有效


[]和下面FelixBecker的评论

上述答案似乎都没有正确序列化错误原型上的属性(因为
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}}}  
var myError=Error('hello');
myError.causedBy=错误('error2');
myError.causedBy.causedBy=错误('error3');
myError.causedBy.causedBy.displayed=true;
stringify(myError);
{“name”:“Error”、“message”:“hello”、“stack”:“Error:hello\n at:66:15”、“causedBy”:{“name”:“Error”、“message”:“Error:Error 2”、“stack”:“Error:Error 2\n at:67:20”、“causedBy”:{“name”:“Error”、“message”:“error3”、“stack”:“Error:Error:error3\n at:68:29”、“displayed:true}}

有一个很棒的Node.js包用于此:
序列化错误

npm install serialize-error
它甚至可以很好地处理嵌套的错误对象

import {serializeError} from 'serialize-error';

JSON.stringify(serializeError(error));

医生:

因为没有人在谈论为什么部分,所以我要回答这个问题

为什么这个
JSON.stringify
返回一个空对象?

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

根据

对于所有其他对象实例(包括Map、Set、WeakMap和WeakSet),只有它们的可枚举属性将被序列化


而且
Error
对象没有可枚举属性,这就是它打印空对象的原因。

我们需要序列化任意对象层次结构,其中根或层次结构中的任何嵌套属性都可能是错误实例

我们的解决方案是使用
JSON.stringify()
replacer
参数,例如:

函数jsonFriendlyErrorReplacer(键,值){
if(值instanceof Error){
返回{
//拉取所有可枚举属性,支持自定义错误的属性
价值
//显式拉取错误的不可枚举属性
name:value.name,
message:value.message,
stack:value.stack,
}
}
返回值
}
设obj={
错误:新错误('嵌套错误消息')
> JSON.stringify(error);
'{}'
const util = require("util");
...
return JSON.stringify(obj, (name, value) => {
    if (value instanceof Error) {
        return util.format(value);
    } else {
        return value;
    }
}
var error = new Error('simple error message');
var errStringified = (err => JSON.stringify(Object.getOwnPropertyNames(Object.getPrototypeOf(err)).reduce(function(accumulator, currentValue) { return accumulator[currentValue] = err[currentValue], accumulator}, {})))(error);
console.log(errStringified);
import { inspect }  from "util";

const myObject = new Error("This is error");
console.log(JSON.stringify(myObject)); // Will print {}
console.log(myObject); // Will print full error object
console.log(inspect(myObject, {depth: null})); // Same output as console.log plus it works as well for objects with many nested properties.