Учитывая строку данных JSON, как я могу безопасно превратить эту строку в объект JavaScript?
Очевидно, я могу сделать это небезопасно с помощью чего-то вроде:
var obj = eval("(" + json + ')');
но это оставляет меня уязвимым для строки JSON, содержащей другой код, который кажется очень опасным просто eval.
Хорошо, сейчас 2014 год, и вы никогда не должны использовать eval для анализа строки JSON, потому что вы подвергнете свой код «внедрению кода». Вместо этого используйте JSON.parse(yourString).
Являются ли данные JSON буквальными?
@shanechiu: если вы имеете в виду скалярный тип данных, да, это так. Это просто строка с синтаксисом "ключ-значение".
См. Документацию по методу parse() [w3schools.com/js/js_json_parse.asp].



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я не уверен насчет других способов сделать это, но вот как это сделать в Прототип (учебник JSON).
new Ajax.Request('/some_url', {
method:'get',
requestHeaders: {Accept: 'application/json'},
onSuccess: function(transport){
var json = transport.responseText.evalJSON(true);
}
});
Вызов evalJSON() с истиной в качестве аргумента очищает входящую строку.
Этот ответ предназначен для IE <7, для современных браузеров проверьте ответ Джонатана выше.
Этот ответ устарел, и теперь Джонатан ответ выше (JSON.parse(jsonString)) является лучшим ответом.
JSON.org имеет парсеры JSON для многих языков, включая четыре разных для JavaScript. Я считаю, что большинство людей сочли бы json2.js своей реализацией goto.
Я бы хотел, чтобы люди перестали отрицать этот ответ. Он был точным, когда был опубликован в 2008 году. Просто проголосуйте за новый.
Если ответ сейчас устарел, подумайте о его обновлении.
для IE <8 вам нужно использовать это.
Если вы используете jQuery, вы также можете использовать:
$.getJSON(url, function(data) { });
Тогда вы можете делать такие вещи, как
data.key1.something
data.key1.something_else
и Т. Д.
вы используете jQuery, не так ли?
$.ajax({
url: url,
dataType: 'json',
data: data,
success: callback
});
Обратному вызову передаются возвращенные данные, которые будут объектом или массивом JavaScript, как определено структурой JSON и проанализировано с помощью метода $.parseJSON().
Метод jQuery устарел. Вместо этого используйте этот метод:
let jsonObject = JSON.parse(jsonString);
Исходный ответ с использованием устаревшей функции jQuery:
Если вы используете jQuery, просто используйте:
jQuery.parseJSON( jsonString );
Это именно то, что вы ищете (см. JQuery документация).
Есть ли причина использовать это вместо JSON.parse ()?
jQuery.parseJSON по умолчанию использует JSON.parse, если он существует, поэтому единственная причина использовать его вместо реального - это если вам нужен запасной вариант для <IE7. Это было изменено еще в jQuery 1.6: james.padolsey.com/jquery/#v=1.6.0&fn=jQuery.parseJSON
Обновление 2016: Начиная с jQuery 3.0, $ .parseJSON устарел, и вместо него следует использовать собственный метод JSON.parse.
JSON.parse(jsonString) - это чистый JavaScript-подход, если вы можете гарантировать достаточно современный браузер.
Я почти уверен, что это безопасно для Node.js
Он поддерживается не во всех браузерах, но скрипт по ссылке ниже добавляет его в браузеры, в которых его нет: github.com/douglascrockford/JSON-js/blob/master/json2.js
@vsync, вы понимаете, что это чистый ответ Javascript ТОЛЬКО ... если вы прочитаете описание тега javascript, вы увидите это ... "Если не включен тег для фреймворка / библиотеки, ожидается чистый ответ JavaScript." .. Я даю этому +1, поскольку это единственный ответ javascript .. .
Если вы используете NodeJS, я не могу загрузить jQuery только для синтаксического анализа jsonString в объект JSON. Так что проголосуйте за ответ Джонатана
не поддерживается IE8, некоторыми версиями IE9 и более старыми версиями всех других браузеров
Действительно, JSON есть не в каждом браузере и был добавлен недавно. Чтобы некоторые браузеры поддерживали JSON, вам необходимо загрузить внешнюю библиотеку, например: github.com/douglascrockford/JSON-js
Согласно эта ссылка он поддерживается IE8 +, хотя там написано: Requires document to be in IE8+ standards mode to work in IE8.
Если вы не совсем уверены в источнике json, никогда не помешает иметь блок try / catch для обработки сценариев, в которых json недействителен.
Я думаю, что здесь стоит упомянуть, что было бы неплохо справиться с ошибкой изящно, добавив try{} catch(e){}.
Действительно ли это безопасно от пользовательского контента? Может ли это привести к атаке путем внедрения сценария, например если jsonString - '{"color": "deep </script><script>alert('pwnd!')</script> purple"}'?
@prototype Да, это безопасно, почему бы и нет? Это парсер JSON, а не интерпретатор скриптов.
@amn ты прав, что JSON.parse(str) безопасен сам по себе. Во время моего первоначального комментария мой контекст заключался в том, что если этот фрагмент существует внутри тега <script>, отображаемого на стороне клиента браузера, а str содержит пользовательские данные, возможно, интерполированные шаблоном, тогда части str можно интерпретировать как исполняемый код, stackoverflow.com/a/37920555/645715
Кажется, это проблема:
Ввод, полученный через веб-узел Ajax и т. д., Будет в строковом формате, но вам нужно знать, является ли это JSON.parsable. Проблема в том, что если вы всегда запускаете ее через JSON.parse, программа МОЖЕТ продолжить «успешно», но вы все равно будете видеть ошибку в консоли с ужасным "Error: unexpected token 'x'".
var data;
try {
data = JSON.parse(jqxhr.responseText);
} catch (_error) {}
data || (data = {
message: 'Server error, please retry'
});
НЕТ. Проблема в том, что вы ожидаете объект JSON и можете получить (function(){ postCookiesToHostileServer(); }()); или даже более неприятные вещи в контексте Node.
Ну, JSON.parse очищает ввод функций (что в этом случае не поможет, поскольку это объект IIF ->). Кажется, лучший способ заняться этой темой - попробовать / поймать. (См. Править)
Используйте простой пример кода в "JSON.parse ()":
var jsontext = '{"firstname":"Jesper","surname":"Aaberg","phone":["555-0100","555-0120"]}';
var contact = JSON.parse(jsontext);
и изменив его:
var str = JSON.stringify(arr);
Попробуйте использовать метод с этим объектом данных. пример: Data='{result:true,count:1} '
try {
eval('var obj=' + Data);
console.info(obj.count);
}
catch(e) {
console.info(e.message);
}
Этот метод действительно помогает в Nodejs, когда вы работаете с программированием последовательного порта
Это действительно забавно, как люди зацикливаются на «eval - это зло» и делают все, чтобы этого избежать, даже переписывают всю функциональность eval ..
Является ли консенсус, что этот трюк является безопасным методом преобразования строки в объект JSON? Я мог бы использовать это, поскольку не нужен дополнительный импорт js.
eval or Function is equally vulnerable
undefined; function bye() {...} bye();
Просто для удовольствия, вот способ использования функции:
jsonObject = (new Function('return ' + jsonFormatData))()
Интересный подход, я не уверен, что использовал бы его с доступным JSON.Parse, но приятно видеть, что кто-то думает нестандартно.
Это очень похоже на использование eval для этого и небезопасно. :П
У этого есть все недостатки использования eval, но он более сложен и труден для понимания разработчиками.
Я нашел способ "получше":
В 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'
});
Использование 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);
Самый простой способ с помощью метода 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);
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.info(JSON.parse(response));
Вы получите результат как объект {result: true, count: 1}.
Чтобы использовать этот объект, вы можете назначить его переменной, например obj:
var obj = JSON.parse(response);
Используя obj и оператор точки (.), вы можете получить доступ к свойствам объекта JSON.
Попробуйте запустить команду:
console.info(obj.result);
JSON.parse(jsonString);
json.parse превратится в объект.
Разбор 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 || {};
}
};
Object.prototype.toString.call(input) === '[object Object]' должен быть typeof input === 'object' IMO
typeof input также возвращает объект для null и массивов. Так что это небезопасный способ сделать это.
Ранее вы уже рассматривали случай null и массив является как объект. Если вы хотите его протестировать, вы можете использовать instanceof. Более того, если вы дадите этой функции Array, она поймает и return def, хотя могла бы вернуть идеальный массив.
Мой комментарий был о здравом смысле при ловле предметов. Моя функция может иметь несколько предупреждений, но использование typeof input не является предпочтительным способом обнаружения объектов в целом.
IMO, здравый смысл не использует метод toString() для проверки, является ли переменная объектом или нет. См. AngularJS, jQuery, Подчеркивать или даже разработчики
Несомненно, это работает. Но что, если странная библиотека отменяет toString? Мне кажется ненадежным полагаться на строковое представление объекта при проведении такого рода тестов. Вы используете конкретный случай представления toString, чтобы проверить, является это объектом или нет. Но что, если вы хотите улучшить свою функцию и проверить, является ли это массивом? Вы бы использовали toString вместе с substring?
Хм интересный случай. Было бы как-нибудь, даже если это крошечный шанс. Однако все еще думает, что это более безопасный способ отличать объекты от массивов, поскольку typeof не работает даже с нулевым значением.
У меня работает преобразование объекта в JSON, а затем его синтаксический анализ, например:
JSON.parse(JSON.stringify(object))
Вы пропустили закрывающую скобку.
Официальная документация:
Метод JSON.parse() анализирует строку JSON, создавая значение или объект JavaScript, описываемый строкой. Дополнительная функция reviver может быть предоставлена для выполнения преобразования результирующего объекта перед его возвратом.
Синтаксис:
JSON.parse(text[, reviver])
Параметры:
text
: Строка для синтаксического анализа как JSON. См. Описание синтаксиса JSON в объекте JSON.
reviver (optional)
: Если функция, это определяет, как значение, первоначально созданное в результате синтаксического анализа, преобразуется перед возвратом.
Возвращаемое значение
Объект, соответствующий заданному тексту JSON.
Исключения
Выдает исключение SyntaxError, если строка для синтаксического анализа недействительна JSON.
Я знаю более старый вопрос, но никто не замечает это решение, используя 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 (например, атрибут данных).
Попробуйте это. Это написано в машинописном тексте.
export function safeJsonParse(str: string) {
try {
return JSON.parse(str);
} catch (e) {
return str;
}
}
Я новичок в Машинописи. Какие преимущества это добавляет к JSON.parse()?
Если произошло какое-либо исключение, это вернет саму строку ввода.
@MarcL. насколько мне известно, TypeScript не изменяет JSON.parse () и любые другие системные методы (но я не занимаюсь исследованиями в этом направлении)
Разберите строку JSON с помощью JSON.parse(), и данные станут объектом JavaScript:
JSON.parse(jsonString)
Здесь JSON представляет собой обработку набора данных JSON.
Представьте, что мы получили этот текст с веб-сервера:
'{ "name":"John", "age":30, "city":"New York"}'
Чтобы проанализировать объект JSON:
var obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}');
Здесь obj - это соответствующий объект JSON, который выглядит так:
{ "name":"John", "age":30, "city":"New York"}
Чтобы получить значение, используйте оператор .:
obj.name // John
obj.age //30
Преобразуйте объект JavaScript в строку с помощью JSON.stringify().
Javascript (и браузер, и NodeJS) имеют встроенный объект JSON. На этом объекте есть 2 удобных метода работы с JSON. Это следующие:
JSON.parse() Принимает JSON в качестве аргумента, возвращает объект JSJSON.stringify() Принимает объект JS в качестве аргумента, возвращает объект JSONКроме того, что они очень удобно работают с JSON, их можно использовать и для других целей. Комбинация обоих методов JSON позволяет очень легко создавать глубокие клоны массивов или объектов. Например:
let arr1 = [1, 2, [3 ,4]];
let newArr = arr1.slice();
arr1[2][0] = 'changed';
console.info(newArr); // not a deep clone
let arr2 = [1, 2, [3 ,4]];
let newArrDeepclone = JSON.parse(JSON.stringify(arr2));
arr2[2][0] = 'changed';
console.info(newArrDeepclone); // A deep clone, values unchangedЕсли у нас есть такая строка:
"{\"status\":1,\"token\":\"65b4352b2dfc4957a09add0ce5714059\"}"
тогда мы можем просто дважды использовать JSON.parse для преобразования этой строки в объект JSON:
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
/**
* Safely turning a JSON string into an object
*
* @param {String} str - JSON String
* @returns deserialized object, false if error
*/
export function jsonParse(str) {
let data = null;
try {
data = JSON.parse(str);
} catch (err) {
return false;
}
return data;
}
JSON.parse - это правильный способ преобразовать строку в объект, но если анализируемая строка не является объектом или если строка неверна, то он выдаст ошибку, которая приведет к поломке остальной части кода, так что это идеально подходит для обертывания функции JSON.parse внутри try-catch, например
try{
let obj = JSON.parse(string);
}catch(err){
console.info(err);
}
Просто к синтаксису обложки для разных типов ввода
Анализируйте данные с помощью JSON.parse (), и данные становятся объектом JavaScript.
var obj = JSON.parse('{ "name":"John", "age":30, "city":"New York"}');
При использовании JSON.parse () в JSON, полученном из массива, метод вернет массив JavaScript вместо объекта JavaScript.
var myArr = JSON.parse(this.responseText);
console.info(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 + ")");
На этот вопрос уже есть хороший ответ, но мне было интересно узнать о производительности, и сегодня 2020.09.21 я провожу тесты на MacOs HighSierra 10.13.6 на Chrome v85, Safari v13.1.2 и Firefox v80 для выбранных решений.
eval/Function (A, B, C) быстр в Chrome (но для больших и глубоких объектов N = 1000 они вылетают: «Превышен максимальный вызов стека)eval (A) быстрый / средний во всех браузерахJSON.parse (D, E) - самые быстрые в Safari и FirefoxВыполняю 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.info('obj_ShallowSmall:',JSON.stringify(obj_ShallowSmall));
console.info('obj_DeepSmall:',JSON.stringify(obj_DeepSmall));
console.info('obj_ShallowBig:',JSON.stringify(obj_ShallowBig));
console.info('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.info(
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!А вот примеры результатов для хрома
В большинстве языков eval несет в себе дополнительный риск. Eval оставляет открытую дверь для использования хакерами. ОДНАКО помните, что весь javascript работает на клиенте. ОЖИДАТЬ, что его изменят хакеры. Они могут ОЦЕНИТЬ все, что захотят, просто используя консоль. Вы должны построить свою защиту на стороне сервера.