将JSON反序列化为JavaScript对象

300

我在一个Java服务器应用程序中有一个字符串,可通过AJAX访问。它看起来像以下内容:

var json = [{
    "adjacencies": [
        {
          "nodeTo": "graphnode2",
          "nodeFrom": "graphnode1",
          "data": {
            "$color": "#557EAA"
          }
        }
    ],
    "data": {
      "$color": "#EBB056",
      "$type": "triangle",
      "$dim": 9
    },
    "id": "graphnode1",
    "name": "graphnode1"
},{
    "adjacencies": [],
    "data": {
      "$color": "#EBB056",
      "$type": "triangle",
      "$dim": 9
    },
    "id": "graphnode2",
    "name": "graphnode2"
}];

当从服务器获取字符串时,是否有一种简单的方法将其转换为可用的JavaScript对象(或数组)?还是我必须手动拆分字符串并手动构建对象?


可能是如何在JavaScript中解析JSON的重复问题。 - Felix Kling
可能是在JavaScript中解析JSON?的重复问题。 - m93a
8个回答

444

现代浏览器支持JSON.parse()

var arr_from_json = JSON.parse( json_string );

在不支持 JSON 的浏览器中,你可以引入 json2


例如,对于JSON中的日期字段如何处理呢? {StartDate: "/Date(1372575600000)/"}? - Philipp Munin
@PhilippMunin 你可以使用 JavaScript API 中的此日期函数: new Date(parseInt("/Date(946681200000)/".replace('/Date(', ''))); - Leo
或者Map()对象等,如何进行“正确”的反序列化? - Ewan

27

JSON的整个重点在于,可以将JSON字符串转换为本地对象而不进行任何操作。请查看链接

您可以使用eval(string)JSON.parse(string)

然而,eval是有风险的。来自json.org的说明:

eval函数非常快。 然而,它可以编译和执行任何JavaScript程序, 因此可能存在安全问题。 当源受信任和能力时,建议使用eval。 使用JSON解析器更安全。 在XMLHttpRequest上的Web应用程序中, 只允许与提供该页面的相同来源通信,因此是受信任的。 但它可能不够能力。 如果服务器没有严格遵守其JSON编码, 或者如果它没有严格验证其所有输入, 那么它可能会传递无效的JSON文本, 这可能携带危险的脚本。 eval函数将执行该脚本,释放其恶意。


1
我不理解这个风险。任何人都可以使用JS调试器注入并执行他们想要的任何脚本吗? - xr280xr
4
是的,但这只会在他们的浏览器本地发生,不会影响下载该网站的每个浏览器。 - masterxilo

17

像 jQuery 一样做!(本质)

function parseJSON(data) {
    return window.JSON && window.JSON.parse ? window.JSON.parse( data ) : (new Function("return " + data))(); 
}
// testing
obj = parseJSON('{"name":"John"}');
alert(obj.name);

这种方法不需要任何外部库,而且它仍然可以在旧版浏览器上运行。


9
看起来这似乎是回退到了等价于 eval() 的操作。 - LarsH
1
这很危险,eval很邪恶! - caesarsol

10

你也可以使用 eval(),但是 JSON.parse() 更安全、更容易,那么为什么不用呢?

好用且有效

var yourJsonObject = JSON.parse(json_as_text);

我不明白为什么您会偏爱使用 eval。这只会让您的应用程序面临风险。
话虽如此,这确实是可能的虽然不好,但也可以运行
var yourJsonObject = eval(json_as_text);

为什么使用 eval 是一个糟糕的主意?

考虑以下示例。

一些第三方或用户提供的 JSON 字符串数据。

var json = `
[{
    "adjacencies": [
        {
          "nodeTo": function(){
            return "delete server files - you have been hacked!";
          }(),
          "nodeFrom": "graphnode1",
          "data": {
            "$color": "#557EAA"
          }
        }
    ],
    "data": {
      "$color": "#EBB056",
      "$type": "triangle",
      "$dim": 9
    },
    "id": "graphnode1",
    "name": "graphnode1"
},{
    "adjacencies": [],
    "data": {
      "$color": "#EBB056",
      "$type": "triangle",
      "$dim": 9
    },
    "id": "graphnode2",
    "name": "graphnode2"
}]
`;

您的服务器端脚本处理这些数据。

使用 JSON.parse

window.onload = function(){
  var placeholder = document.getElementById('placeholder1');
  placeholder.innerHTML = JSON.parse(json)[0].adjacencies[0].nodeTo;
}

会抛出以下异常:

Uncaught SyntaxError: Unexpected token u in JSON at position X. 

该函数不会被执行。

您是安全的。

使用eval()

window.onload = function(){
  var placeholder = document.getElementById('placeholder1');
  placeholder.innerHTML = eval(json)[0].adjacencies[0].nodeTo;
}

将执行该函数并返回文本。

如果您在服务器端运行此代码,并且我用一个从您网站文件夹中删除文件或执行其他有害操作的函数替换了这个无害的函数,那么您的应用程序将被黑客攻击。在此示例中不会抛出任何错误/警告。

您是不安全的。

我能够操纵JSON文本字符串,使其作为一个函数在服务器上执行。

eval(JSON)[0].adjacencies[0].nodeTo期望处理JSON字符串,但实际上我们刚刚在我们的服务器上执行了一个函数。

如果我们在服务器端检查所有用户提供的数据,然后再将其传递给eval()函数,也可以避免这种情况,但为什么不使用内置工具来解析JSON并避免所有这些麻烦和危险呢?


谢谢您。我相信这是OWASP Web应用程序风险中的第8项,即反序列化。 - Rahul Purohit
我同意eval很糟糕,但是你不得不写.nodeTo()并加上括号才能让它作为一个函数执行吗? - aaaantoine

8
收集数组中的所有项并返回一个 JSON 对象。
collectData: function (arrayElements) {

        var main = [];

        for (var i = 0; i < arrayElements.length; i++) {
            var data = {};
            this.e = arrayElements[i];            
            data.text = arrayElements[i].text;
            data.val = arrayElements[i].value;
            main[i] = data;
        }
        return main;
    },

为了解析相同的数据,我们需要按照以下步骤进行操作

dummyParse: function (json) {       
        var o = JSON.parse(json); //conerted the string into JSON object        
        $.each(o, function () {
            inner = this;
            $.each(inner, function (index) {
                alert(this.text)
            });
        });

}

2

如果你想让反序列化的对象也有函数,你可以使用我的小工具:https://github.com/khayll/jsmix

//first you'll need to define your model
var GraphNode = function() {};
GraphNode.prototype.getType = function() {
   return this.$type;
}

var Adjacency = function() {};
Adjacency.prototype.getData =n function() {
    return this.data;
}

//then you could say:
var result = JSMix(jsonData)
    .withObject(GraphNode.prototype, "*")
    .withObject(Adjacency.prototype, "*.adjacencies")
    .build();

//and use them
console.log(result[1][0].getData());

0

如果您将字符串粘贴到服务器端的HTML中,则无需执行任何操作:

对于JSP中的普通Java:

var jsonObj=<%=jsonStringInJavaServlet%>;

关于 Struts 的 JSP 宽度:

var jsonObj=<s:property value="jsonStringInJavaServlet" escape="false" escapeHtml="false"/>;

-3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接