安全地将 JSON 字符串转换为对象

Safely turning a JSON string into an object

提问人:Matt Sheppard 提问时间:9/5/2008 最后编辑:Kamil KiełczewskiMatt Sheppard 更新时间:9/21/2022 访问量:1446806

问:

给定一串 JSON 数据,如何安全地将该字符串转换为 JavaScript 对象?

显然,我可以通过以下方式不安全地做到这一点:

var obj = eval("(" + json + ')');

但这让我容易受到包含其他代码的 JSON 字符串的影响,简单地计算它似乎非常危险。

JavaScript JSON 解析

评论

86赞 Beachhouse 2/8/2013
在大多数语言中,eval 会带来额外的风险。Eval 为黑客利用留下了一扇敞开的大门。但是,请记住,所有 javascript 都在客户端上运行。预计它会被黑客改变。他们只需使用控制台即可对任何他们想要的东西进行评估。您必须在服务器端构建保护。
24赞 Daniel 10/22/2014
好的,现在是 2014 年,你永远不应该使用来解析 JSON 字符串,因为你会将你的代码暴露给“代码注入”。请改用。evalJSON.parse(yourString)
1赞 shanechiu 9/25/2017
JSON数据是文字吗?
1赞 0zkr PM 9/18/2018
@shanechiu:如果你指的是标量数据类型,是的。只是一个包含键值语法的字符串。
1赞 Ale Gu 7/18/2020
请参阅有关该方法的文档:w3schools.com/js/js_json_parse.aspparse()

答:

25赞 Mark Biek 9/5/2008 #1

我不确定其他方法可以做到这一点,但这是您在原型(JSON 教程)中如何做到这一点。

new Ajax.Request('/some_url', {
  method:'get',
  requestHeaders: {Accept: 'application/json'},
  onSuccess: function(transport){
    var json = transport.responseText.evalJSON(true);
  }
});

使用 true 作为参数进行调用会清理传入的字符串。evalJSON()

169赞 John 9/5/2008 #2

这个答案是针对 IE < 7 的,对于现代浏览器,请查看上面 Jonathan 的答案。

这个答案已经过时了,Jonathan 上面的答案 (JSON.parse(jsonString)) 现在是最好的答案

JSON.org 具有适用于多种语言的 JSON 解析器,包括四种不同的 JavaScript 解析器。我相信大多数人会认为 json2.js 是他们的首选实现。

评论

33赞 John 1/16/2015
我希望人们不要再对这个答案投反对票了。它在 2008 年发布时是准确的。只需为新的投票即可。
25赞 Sotirios Delimanolis 3/7/2015
如果答案现在已经过时,请考虑更新它。
4赞 Mahmood Dehghan 7/17/2015
对于 IE < 8,您需要使用它。
21赞 Leanan 10/24/2008 #3

如果您使用的是 jQuery,您还可以使用:

$.getJSON(url, function(data) { });

然后你可以做这样的事情

data.key1.something
data.key1.something_else

等。

评论

1赞 Alexandre C. 9/2/2010
你正在使用jQuery,不是吗?
17赞 Prahlad 5/6/2010 #4
$.ajax({
  url: url,
  dataType: 'json',
  data: data,
  success: callback
});

回调传递返回的数据,该数据将是 JSON 结构定义并使用该方法解析的 JavaScript 对象或数组。$.parseJSON()

902赞 Alex V 9/2/2010 #5

jQuery 方法现已弃用。请改用此方法:

let jsonObject = JSON.parse(jsonString);

使用已弃用的 jQuery 功能的原始答案

如果您使用的是jQuery,请使用:

jQuery.parseJSON( jsonString );

这正是你要找的(参见jQuery文档)。

评论

9赞 Jon 3/20/2016
是否有理由在 JSON.parse() 上使用它?
10赞 Karl-Johan Sjögren 4/6/2016
jQuery.parseJSON如果存在,则默认使用 use,因此使用它而不是实际的唯一原因是如果您需要 <IE7 的回退。它早在jQuery 1.6中就被更改了: james.padolsey.com/jquery/#v=1.6.0&fn=jQuery.parseJSONJSON.parse
13赞 jkdev 6/29/2016
2016 年更新:从 jQuery 3.0 开始,$.parseJSON 已弃用,您应该改用本机 JSON.parse 方法。
2117赞 Jonathan. 4/16/2011 #6

JSON.parse(jsonString) 是一种纯 JavaScript 方法,只要你能保证一个相当现代的浏览器。

评论

79赞 Stephen 10/19/2011
我很确定它对 Node.js 是安全的
3赞 speedplane 1/12/2013
并非所有浏览器都支持它,但以下链接中的脚本会将其添加到没有它的浏览器中: github.com/douglascrockford/JSON-js/blob/master/json2.js
6赞 Redsandro 10/8/2013
使用起来非常安全
14赞 Antony 10/16/2013
如果您正在使用 NodeJS,我不可能仅仅为了将 jsonString 解析为 JSON 对象而加载 jQuery。所以对乔纳森的回答投赞成票
6赞 JoshuaDavid 1/13/2015
根据此链接,IE8+支持它,尽管它说:Requires document to be in IE8+ standards mode to work in IE8.
27赞 Cody 4/29/2013 #7

这似乎是问题所在:

通过 Ajax websocket 等接收的输入,它将是 String 格式,但您需要知道它是否是 .问题是,如果您总是运行它,程序可能会“成功”继续,但您仍然会在控制台中看到一个错误,并带有可怕的.JSON.parsableJSON.parse"Error: unexpected token 'x'"

var data;

try {
  data = JSON.parse(jqxhr.responseText);
} catch (_error) {}

data || (data = {
  message: 'Server error, please retry'
});

评论

0赞 Yaur 4/16/2014
不。问题是你期待一个JSON对象,最终可能会在Node的上下文中得到甚至更讨厌的东西。(function(){ postCookiesToHostileServer(); }());
0赞 Cody 4/25/2014
好吧,JSON.parse 会清理函数的输入(在这种情况下,这无济于事,因为它是 IIF --> 对象)。似乎解决这个问题的最好方法是尝试/捕捉。(见编辑)
80赞 Ronald Coarite 12/16/2013 #8

使用“JSON.parse()”中的简单代码示例:

var jsontext = '{"firstname":"Jesper","surname":"Aaberg","phone":["555-0100","555-0120"]}';
var contact = JSON.parse(jsontext);

并反转它:

var str = JSON.stringify(arr);
10赞 GPrathap 7/16/2014 #9

尝试将该方法与此 Data 对象一起使用。前任:Data='{result:true,count:1}'

try {
  eval('var obj=' + Data);
  console.log(obj.count);
}
catch(e) {
  console.log(e.message);
}

当您使用串行端口编程时,此方法在 Nodejs 中非常有用

评论

0赞 diynevala 9/12/2014
有趣的是,人们执着于“eval 是邪恶的”,他们会做任何事情来避免它,甚至重写整个 eval 功能。
0赞 Whome 10/13/2014
共识这个技巧是将字符串转换为JSON对象的安全方法吗?我可以使用它,因为不需要额外的 js 导入。
1赞 Slai 6/3/2018
任何使用或同样易受攻击的方法evalFunction
1赞 Salvioner 1/22/2019
undefined; function bye() {...} bye();
19赞 lessisawesome 10/15/2014 #10

只是为了好玩,这里有一个使用函数的方法:

 jsonObject = (new Function('return ' + jsonFormatData))()

评论

3赞 9/3/2015
有趣的方法,我不确定我是否会将其与 JSON 一起使用。解析可用,但很高兴看到有人跳出框框思考。
7赞 Nebula 11/7/2015
这与仅仅使用它非常相似,并且不安全。:Peval
10赞 Quentin 11/24/2015
这具有使用的所有缺点,但对于维护者来说更复杂、更难理解。eval
5赞 Dorian 2/18/2015 #11

我找到了一种“更好”的方法:

在 CoffeeScript 中:

try data = JSON.parse(jqxhr.responseText)
data ||= { message: 'Server error, please retry' }

在 Javascript 中:

var data;

try {
  data = JSON.parse(jqxhr.responseText);
} catch (_error) {}

data || (data = {
  message: 'Server error, please retry'
});
18赞 Barath Kumar 4/22/2015 #12

使用可能是最好的方法。JSON.parse

下面是一个示例

var jsonRes = '{ "students" : [' +
          '{ "firstName":"Michel" , "lastName":"John" ,"age":18},' +
          '{ "firstName":"Richard" , "lastName":"Joe","age":20 },' +
          '{ "firstName":"James" , "lastName":"Henry","age":15 } ]}';
var studentObject = JSON.parse(jsonRes);
10赞 Jorgesys 2/20/2016 #13

最简单的使用方法:parse()

var response = '{"result":true,"count":1}';
var JsonObject= JSON.parse(response);

然后,您可以获取 JSON 元素的值,例如:

var myResponseResult = JsonObject.result;
var myResponseCount = JsonObject.count;

使用 jQuery,如 jQuery.parseJSON() 文档中所述:

JSON.parse(jsonString);
4赞 Pushkar Kathuria 12/3/2016 #14

JSON.parse()将传递到函数中的任何 JSON 字符串转换为 JSON 对象。

为了更好地理解它,请按 在浏览器中打开“检查元素”,然后转到控制台编写以下命令:F12

var response = '{"result":true,"count":1}'; //sample json object(string form)
JSON.parse(response); //converts passed string to JSON Object.

现在运行以下命令:

console.log(JSON.parse(response));

您将获得作为 Object 的输出。{result: true, count: 1}

为了使用该对象,您可以将其分配给变量,例如:obj

var obj = JSON.parse(response);

通过使用 和 点 () 运算符,您可以访问 JSON 对象的属性。obj.

尝试运行以下命令:

console.log(obj.result);
4赞 Shekhar Tyagi 12/19/2016 #15
JSON.parse(jsonString);

json.parse 将变为 object。

5赞 Tahsin Turkoz 2/15/2017 #16

JSON解析总是很痛苦。如果输入与预期不符,则会引发错误并导致您正在执行的操作崩溃。

您可以使用以下小函数来安全地解析您的输入。即使输入无效或已经是对象,它也总是转动一个对象,这在大多数情况下更好:

JSON.safeParse = function (input, def) {
  // Convert null to empty object
  if (!input) {
    return def || {};
  } else if (Object.prototype.toString.call(input) === '[object Object]') {
    return input;
  }
  try {
    return JSON.parse(input);
  } catch (e) {
    return def || {};
  }
};

评论

0赞 Serge K. 12/7/2017
Object.prototype.toString.call(input) === '[object Object]'应该是IMOtypeof input === 'object'
0赞 Tahsin Turkoz 1/10/2018
typeof 输入也返回 null 和数组的对象。所以这不是安全的方式。
0赞 Serge K. 1/10/2018
您之前已经介绍了这种情况,数组是一个 Object。如果要测试它,可以使用 .此外,如果你给这个函数一个 ,它将捕获 以及它何时可以返回完美的数组。nullinstanceofArrayreturn def
0赞 Tahsin Turkoz 1/10/2018
我的评论是关于捕捉物体时的常识。我的函数可以有多种预防措施,但通常使用 typeof 输入不是检测对象的首选方法。
0赞 Serge K. 1/10/2018
IMO,常识不使用方法来检查变量是否是对象。参见 AngularJSjQueryUnderscore,甚至 devstoString()
2赞 Liuver Reynier Durán Pérez 6/20/2017 #17

将对象转换为JSON,然后解析它对我有用,例如:

JSON.parse(JSON.stringify(object))
1赞 Durgpal Singh 7/26/2017 #18

您还可以使用函数进行过滤。reviver

var data = JSON.parse(jsonString, function reviver(key, value) {
   //your code here to filter
});

有关更多信息,请阅读 JSON.parse

4赞 Salomon Zhang 12/20/2017 #19

官方文档

该方法分析 JSON 字符串,构造字符串描述的 JavaScript 值或对象。可以提供一个可选函数,用于在返回结果对象之前对结果对象执行转换。JSON.parse()reviver

语法:

JSON.parse(text[, reviver])

参数:

text:要解析为 JSON 的字符串。有关 JSON 语法的说明,请参阅 JSON 对象。

reviver (optional):如果是函数,则规定最初通过解析生成的值在返回之前如何转换。

返回值

与给定 JSON 文本对应的 Object。

异常

如果要分析的字符串不是有效的 JSON,则引发 SyntaxError 异常。

1赞 Codebeat 2/19/2018 #20

我知道较旧的问题,但是没有人通过使用返回数据的匿名函数来注意到此解决方案。new Function()


举个例子:

 var oData = 'test1:"This is my object",test2:"This is my object"';

 if( typeof oData !== 'object' )
  try {
   oData = (new Function('return {'+oData+'};'))();
  }
  catch(e) { oData=false; }

 if( typeof oData !== 'object' )
  { alert( 'Error in code' ); }
 else {
        alert( oData.test1 );
        alert( oData.test2 );
      }

这更安全一些,因为它在函数内部执行,而不是直接在代码中编译。因此,如果其中有函数声明,则不会绑定到默认的窗口对象。

我用它来简单快速地“编译”DOM元素(例如数据属性)的配置设置。

-4赞 Supun Dharmarathne 5/30/2018 #21

试试这个。这是用打字稿写的。

export function safeJsonParse(str: string) {
    try {
        return JSON.parse(str);
    } catch (e) {
        return str;
    }
}

评论

0赞 Marc L. 10/19/2018
我是 Typescript 的新手。这有什么好处?JSON.parse()
0赞 Supun Dharmarathne 10/31/2018
如果发生任何异常,这将返回输入字符串本身
0赞 Kamil Kiełczewski 9/26/2020
@MarcL。据我所知,TypeScript 不会修改 JSON.parse() 和任何其他系统方法(但我不朝这个方向进行研究)
5赞 Amitesh Bharti 8/13/2018 #22

使用 解析 JSON 字符串,数据将变成 JavaScript 对象:JSON.parse()

JSON.parse(jsonString)

这里,JSON表示处理JSON数据集。

想象一下,我们从 Web 服务器收到了以下文本:

'{ "name":"John", "age":30, "city":"New York"}'

要解析为 JSON 对象,请执行以下操作:

var obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}'); 

下面是相应的 JSON 对象,如下所示:obj

{ "name":"John", "age":30, "city":"New York"}

若要获取值,请使用运算符:.

obj.name // John
obj.age //30

使用 将 JavaScript 对象转换为字符串。JSON.stringify()

1赞 Willem van der Veen 8/18/2018 #23

总结:

Javascript(浏览器和 NodeJS)都有一个内置对象。在这个对象上有 2 种方便的处理方法。它们如下:JSONJSON

  1. JSON.parse()作为参数,返回JS对象JSON
  2. JSON.stringify()以JS对象为参数返回对象JSON

其他应用:

此外,为了非常方便地处理它们,它们可以用于其他手段。这两种方法的结合使我们能够非常容易地进行数组或对象的深度克隆。例如:JSONJSON

let arr1 = [1, 2, [3 ,4]];
let newArr = arr1.slice();

arr1[2][0] = 'changed'; 
console.log(newArr); // not a deep clone

let arr2 = [1, 2, [3 ,4]];
let newArrDeepclone = JSON.parse(JSON.stringify(arr2));

arr2[2][0] = 'changed'; 
console.log(newArrDeepclone); // A deep clone, values unchanged

3赞 Hamid Araghi 3/15/2019 #24

如果我们有一个这样的字符串:

"{\"status\":1,\"token\":\"65b4352b2dfc4957a09add0ce5714059\"}"

那么我们可以简单地使用 twice 将这个字符串转换为 JSON 对象:JSON.parse

var sampleString = "{\"status\":1,\"token\":\"65b4352b2dfc4957a09add0ce5714059\"}"
var jsonString= JSON.parse(sampleString)
var jsonObject= JSON.parse(jsonString)

我们可以使用以下方法从 JSON 对象中提取值:

// instead of last JSON.parse:
var { status, token } = JSON.parse(jsonString);

结果将是:

status = 1 and token = 65b4352b2dfc4957a09add0ce5714059
2赞 MOnkey 2/23/2020 #25

只是为了不同的输入类型进行封面解析

使用 JSON.parse() 解析数据,数据成为 JavaScript 对象。

var obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}');

在派生自数组的 JSON 上使用 JSON.parse() 时,该方法将返回一个 JavaScript 数组,而不是一个 JavaScript 对象。

var myArr = JSON.parse(this.responseText);
console.log(myArr[0]);

JSON 中不允许使用日期对象。 对于日期,请执行如下操作

var text = '{ "name":"John", "birth":"1986-12-14", "city":"New York"}';
var obj = JSON.parse(text);
obj.birth = new Date(obj.birth);

JSON 中不允许使用函数。 如果需要包含函数,请将其编写为字符串。

var text = '{ "name":"John", "age":"function () {return 30;}", "city":"New York"}';
var obj = JSON.parse(text);
obj.age = eval("(" + obj.age + ")");
3赞 Kamil Kiełczewski 9/21/2020 #26

性能

这个问题已经有很好的答案,但我对性能感到好奇,今天 2020.09.21 我在 Chrome v10.13.6、Safari v13.1.2 和 Firefox v80 上的 MacOs HighSierra 80 上进行了测试,以选择解决方案。

结果

  • eval/Function(A,B,C) 方法在 Chrome 上很快(但对于大深度对象 N=1000,它们会崩溃:“超出最大堆栈调用)
  • eval(A) 在所有浏览器上都是快/中快
  • JSON.parse(D,E) 在 Safari 和 Firefox 上速度最快

enter image description here

我执行 4 个测试用例:

上述测试中使用的对象来自这里

let obj_ShallowSmall = {
  field0: false,
  field1: true,
  field2: 1,
  field3: 0,
  field4: null,
  field5: [],
  field6: {},
  field7: "text7",
  field8: "text8",
}

let obj_DeepSmall = {
  level0: {
   level1: {
    level2: {
     level3: {
      level4: {
       level5: {
        level6: {
         level7: {
          level8: {
           level9: [[[[[[[[[['abc']]]]]]]]]],
  }}}}}}}}},
};

let obj_ShallowBig = Array(1000).fill(0).reduce((a,c,i) => (a['field'+i]=getField(i),a) ,{});


let obj_DeepBig = genDeepObject(1000);



// ------------------
// Show objects
// ------------------

console.log('obj_ShallowSmall:',JSON.stringify(obj_ShallowSmall));
console.log('obj_DeepSmall:',JSON.stringify(obj_DeepSmall));
console.log('obj_ShallowBig:',JSON.stringify(obj_ShallowBig));
console.log('obj_DeepBig:',JSON.stringify(obj_DeepBig));




// ------------------
// HELPERS
// ------------------

function getField(k) {
  let i=k%10;
  if(i==0) return false;
  if(i==1) return true;
  if(i==2) return k;
  if(i==3) return 0;
  if(i==4) return null;
  if(i==5) return [];
  if(i==6) return {};  
  if(i>=7) return "text"+k;
}

function genDeepObject(N) {
  // generate: {level0:{level1:{...levelN: {end:[[[...N-times...['abc']...]]] }}}...}}}
  let obj={};
  let o=obj;
  let arr = [];
  let a=arr;

  for(let i=0; i<N; i++) {
    o['level'+i]={};
    o=o['level'+i];
    let aa=[];
    a.push(aa);
    a=aa;
  }

  a[0]='abc';
  o['end']=arr;
  return obj;
}

以下代码片段介绍了选定的解决方案

// src: https://stackoverflow.com/q/45015/860099
function A(json) {
  return eval("(" + json + ')');
}

// https://stackoverflow.com/a/26377600/860099
function B(json) {
  return (new Function('return ('+json+')'))()
}


// improved https://stackoverflow.com/a/26377600/860099
function C(json) {
  return Function('return ('+json+')')()
}

// src: https://stackoverflow.com/a/5686237/860099
function D(json) {
  return JSON.parse(json);
}

// src: https://stackoverflow.com/a/233630/860099
function E(json) {
  return $.parseJSON(json)
}



 
// --------------------
// TEST
// --------------------

let json = '{"a":"abc","b":"123","d":[1,2,3],"e":{"a":1,"b":2,"c":3}}';

[A,B,C,D,E].map(f=> {  
  console.log(
    f.name + ' ' + JSON.stringify(f(json))
  )})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
This shippet only presents functions used in performance tests - it not perform tests itself!

以下是 chrome 的示例结果

enter image description here

0赞 user17773570 8/10/2022 #27

另一种选择

const json = '{ "fruit": "pineapple", "fingers": 10 }'
let j0s,j1s,j2s,j3s
console.log(`{ "${j0s="fruit"}": "${j1s="pineapple"}", "${j2s="fingers"}": ${j3s="10"} }`)

2赞 samnoon 9/21/2022 #28

在 JavaScript 中解析 JSON 的推荐方法是使用 JSON.parse()

背景

JSON API 是在 ECMAScript 5 中引入的,此后在市场份额为 >99% 的浏览器中实现了。

jQuery 曾经有一个 $.parseJSON() 函数,但在 jQuery 3.0 中被弃用了。无论如何,在很长一段时间里,它只不过是一个包装.JSON.parse()

const json = '{ "city": "Boston", "population": 500000 }';
const object = JSON.parse(json);
console.log(object.city, object.population);


浏览器兼容性

所有主流浏览器都支持 JSON.parse 吗?

差不多,是的(见参考资料)。