给定一个JSON数据字符串,如何安全地将该字符串转换为JavaScript对象?
很明显,我可以用这样的方式来做这件事:
var obj = eval("(" + json + ')');
但这让我很容易受到包含其他代码的JSON字符串的攻击,简单地eval似乎非常危险。
给定一个JSON数据字符串,如何安全地将该字符串转换为JavaScript对象?
很明显,我可以用这样的方式来做这件事:
var obj = eval("(" + json + ')');
但这让我很容易受到包含其他代码的JSON字符串的攻击,简单地eval似乎非常危险。
当前回答
如果使用jQuery,还可以使用:
$.getJSON(url, function(data) { });
然后你可以做类似的事情
data.key1.something
data.key1.something_else
etc.
其他回答
表演
这个问题已经有了很好的答案,但我对性能很好奇,今天2020.09.21我在Chrome v85、Safari v13.1.2和Firefox v80上对MacOs HighSierra 10.13.6进行了测试,以确定所选的解决方案。
后果
eval/Function(A,B,C)方法在Chrome上很快(但对于大深度对象N=1000,它们会崩溃:“最大堆栈调用超过”)eval(A)在所有浏览器上都是快速/中等速度JSON.parse(D,E)在Safari和Firefox上速度最快
细节
我执行4个测试用例:
对于小的浅对象对于这里的小深对象对于这里的大型浅层物体对于这里的大深度对象
上述测试中使用的对象来自HERE
let obj_ShallowSmall={字段0:假,字段1:真,字段2:1,字段3:0,字段4:空,字段5:[],字段6:{},field7:“text7”,字段8:“text8”,}让obj_DepSmall={级别0:{级别1:{级别2:{级别3:{级别4:{级别5:{级别6:{第7级:{级别8:{第9级:[[[[[[[[]],}}}}}}}}},};让obj_ShallowBig=数组(1000).fill(0).reduce((a,c,i)=>(a['field'+i]=getField(i),a),{});让obj_DepBig=genDeepObject(1000);// ------------------//显示对象// ------------------console.log('obj_ShallowSmall:',JSON.stringify(obj_SharlowSmall));console.log('obj_DepSmall:',JSON.stringify(obj_DeepSmall));console.log('obj_ShallowBig:',JSON.stringify(obj_SharlowBig));console.log('obj_DepBig:',JSON.stringify(obj_DeepBig));// ------------------//助手// ------------------函数getField(k){设i=k%10;如果(i==0)返回false;如果(i==1)返回真;如果(i==2)返回k;如果(i==3)返回0;如果(i==4)返回null;如果(i==5)返回[];如果(i==6)返回{};如果(i>=7)返回“text”+k;}函数genDeepObject(N){//生成:{level0:{level1:{…levelN:{end:[[[…N次…['abc']…]]}}}}…}}让obj={};设o=obj;设arr=[];设a=arr;for(设i=0;i<N;i++){o['level'+i]={};o=o['level'+i];设aa=[];a.推(aa);a=aa;}a[0]=“公元前”;o['end']=arr;返回obj;}
下面的片段显示了所选的解决方案
//第三节:https://stackoverflow.com/q/45015/860099函数A(json){return eval(“(”+json+')');}// https://stackoverflow.com/a/26377600/860099函数B(json){return(新函数('return('+json+')'))()}//改进的https://stackoverflow.com/a/26377600/860099函数C(json){return函数('return('+json+')')()}//第三节:https://stackoverflow.com/a/5686237/860099函数D(json){返回JSON.parse(JSON);}//第三节:https://stackoverflow.com/a/233630/860099函数E(json){return$.parseJSON(json)}// --------------------//测试// --------------------让json=“{“a”:“abc”,“b”:“123”,“d”:[1,2,3],“e”:{”a“:1,”b“:2,”c“:3}}”;[A,B,C,D,E]映射(f=>{控制台日志(f.name+“”+JSON.stringfy(f(JSON)))})<script src=“https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js“></script>此shippet只显示性能测试中使用的函数,而不执行测试本身!
下面是铬的示例结果
只要你能保证一个相当现代的浏览器,JSON.parse(jsonString)就是一种纯JavaScript方法。
另一种选择
const json=“{”水果“:”菠萝“,”手指“:10}”让j0s,j1s,j2s,j3sconsole.log(`{“${j0s=“fruit”}”:“${j1s=“菠萝”}”,“${j2s=“fingers”}”:${j3s=“10”}}`)
这似乎是一个问题:
通过Ajax websocket等接收的输入,它将是字符串格式,但您需要知道它是否是JSON.parsable。问题是,如果您始终通过JSON.parse运行它,程序可能会“成功”继续运行,但您仍然会看到控制台中抛出一个错误,显示可怕的“错误:意外标记'x'”。
var data;
try {
data = JSON.parse(jqxhr.responseText);
} catch (_error) {}
data || (data = {
message: 'Server error, please retry'
});
我不确定是否有其他方法可以做到这一点,但以下是在Prototype(JSON教程)中如何做到的。
new Ajax.Request('/some_url', {
method:'get',
requestHeaders: {Accept: 'application/json'},
onSuccess: function(transport){
var json = transport.responseText.evalJSON(true);
}
});
使用true作为参数调用evalJSON()将净化传入字符串。