jQuery не будет анализировать мой JSON из запроса AJAX

88

Мне трудно разобрать некоторые данные JSON, возвращаемые с моего сервера, с помощью jQuery.ajax ()

Для выполнения AJAX я использую:

$.ajax({
  url: myUrl,
  cache: false,
  dataType: "json",
  success: function(data){
    ...
  },
  error: function(e, xhr){
    ...
  }
});  

И если я верну массив элементов, он будет работать нормально:

[ { title: "One", key: "1" }, { title: "Two", key: "2" } ]

Функция успеха вызывается и получает правильный объект.

Однако, когда я пытаюсь вернуть один объект:

{ title: "One", key: "1" } 

Вызывается функция ошибки, и xhr содержит "parsererror". Я пробовал заключать JSON в скобки на сервере перед отправкой по сети, но это не имеет значения. Тем не менее, если я вставляю контент в строку в Javascript, а затем использую функцию eval (), она отлично его оценивает.

Есть идеи, что я делаю не так?

Энтони

Littlecharva
источник
По теме: stackoverflow.com/questions/631418/…
Майкл Майерс

Ответы:

72

Ваш сервер отправляет данные как Content-Type "*/json"? Если нет, измените заголовки ответа соответствующим образом. "application/json"Например, отправка подойдет .

Томалак
источник
Во-вторых, у этой догадки однажды была такая же проблема, и я узнал, что на удивление использовал неправильный тип пантомимы. Помните об этом, если вы тестируете localhost в Windows. Попробуйте загрузить его куда-нибудь и снова протестировать. Если вы хотите, чтобы он работал на localhost, вам нужно действительно обмануть запрос.
Джош
51

Согласно спецификации json.org , ваш возврат недействителен. Имена всегда цитируются, поэтому вам следует возвращаться

{ "title": "One", "key": "1" }

а также

[ { "title": "One", "key": "1" }, { "title": "Two", "key": "2" } ]

Возможно, это не проблема вашей настройки, поскольку вы говорите, что один из них работает сейчас, но его следует исправить для правильности на случай, если вам понадобится переключиться на другой парсер JSON в будущем.

Бен Комби
источник
2
Действительно, в jQuery 1.4 (например) { key: 'val' }недопустим JSON.
rfunduk
34

Строки JSON обернуты двойные кавычки; одинарные кавычки не являются допустимой заменой.

{"who": "Hello World"}

действительно, но это не так ...

{'who': 'Hello World'}

Хотя это не проблема OP, подумал, что стоит отметить это для других, которые приземляются здесь.

Джон Ми
источник
30

Обычно эта проблема возникает из-за того, что ваш запрос получил неправильный тип MIME. При разработке на вашем собственном компьютере иногда вы не получаете правильный тип mime от «сервера», которым является ваш собственный компьютер. Однажды я столкнулся с этой проблемой при разработке, открыв локально сохраненный файл в браузере (например, URL-адрес был «c: /project/test.html»).

Попробуйте использовать свойство beforeSend, чтобы добавить функцию обратного вызова, которая переопределяет тип mime. Это заставит код работать с json, несмотря на то, что сервер отправляет неправильный тип mime и получает его вызывающий код. Пример кода ниже.

Правильный тип mime - application / json в соответствии с этим вопросом , но я знаю, что application / j-son работало, когда я его пробовал (сейчас несколько лет назад). Возможно, вам сначала следует попробовать application / json.

var jsonMimeType = "application/json;charset=UTF-8";
$.ajax({
 type: "GET",
 url: myURL,
 beforeSend: function(x) {
  if(x && x.overrideMimeType) {
   x.overrideMimeType(jsonMimeType);
  }
 },
 dataType: "json",
 success: function(data){
  // do stuff...
 }
});
Джош
источник
просто хочу сказать, что предложение beforeSend, которое вы предлагаете, сработало для меня !! мой вызов ajax отлично работал в сафари и хром, но не в firefox. как только я добавил beforeSend, Firefox сразу же взлетел. Вау!! Благодарность!!
Кармен Блейк
7

У меня была эта проблема, и я немного использовал

eval('('+data+')')

чтобы получить данные, возвращенные в объекте. но позже возникли другие проблемы с получением ошибки «отсутствует) в скобках», и выяснилось, что jQuery имеет функцию, специально предназначенную для оценки строки для структуры json:

$.parseJSON(data)

должен сделать свое дело. Конечно, это в дополнение к тому, что ваша строка json имеет правильный формат ..

Джубайр
источник
6

Если вы повторяете ответ json и ваши заголовки не совпадают с * / json, вы можете использовать встроенный api jQuery.parseJSON для анализа ответа.

response = '{"name":"John"}';
var obj = jQuery.parseJSON(response);
alert( obj.name === "John" );
Неззи
источник
4
{ title: "One", key: "1" }

Это не то, что вы думаете. Как выражение это литерал объекта, но как выражение это:

{                // new block
    title:       // define a label called 'title' for goto statements
        "One",   // statement: the start of an expression which will be ignored
        key:     // ...er, what? you can't have a goto label in the middle of an expression
                 // ERROR

К сожалению, eval () не дает вам возможности указать, даете ли вы ему инструкцию или выражение, и он имеет тенденцию ошибаться.

Обычное решение - действительно заключить что-либо в круглые скобки перед отправкой в ​​функцию eval (). Вы говорите, что пробовали это на сервере ... явно почему-то этого не происходит. Он должен быть водонепроницаемым, чтобы сказать на стороне клиента, что бы ни получал ответ XMLHttpRequest:

eval('('+responseText+')');

вместо того:

eval(responseText);

пока ответ действительно является выражением, а не утверждением. (например, в нем нет нескольких предложений, разделенных точкой с запятой или новой строкой.)

бобинс
источник
Я думаю, что jQuery автоматически добавляет круглые скобки при обработке данных запроса.
Strager
2
Этот ответ был мне очень полезен, поскольку я никогда не понимал, почему люди заключают JSON в круглые скобки.
Андрей Таранцов
3

Вам нужно будет установить тип содержимого заголовка в вашем php следующим образом:

 <?php

 header('Content-type:application/json');

 ?>

Посмотрите это видео, чтобы лучше понять ....

Ссылка: http://www.youtube.com/watch?v=EvFXWqEqh6o

user3612872
источник
2

Если вы используете веб-службы ASP.NET с помощью jQuery, убедитесь, что в ваш web.config включено следующее:

<webServices>
    <protocols>
        <add name="HttpGet"/>
        <add name="HttpPost"/>
    </protocols>
</webServices>
Андреас Греч
источник
2

У меня была аналогичная проблема, когда Firefox 3.5 работал нормально и анализировал мои данные JSON, но Firefox 3.0.6 возвращал ошибку parseerror. Оказалось, что это пустое место в начале JSON, из-за которого Firefox 3.0.6 выдал ошибку. Удаление пустого места исправило его

Джонбурни
источник
2

Методы eval () и JSON.parse () используют взаимоисключающие форматы.

  • Круглые скобки "eval ()" обязательны .
  • Скобки с «JSON.parse ()» запрещены .

Остерегайтесь, есть функции "stringify ()", которые производят формат "eval". Для ajax следует использовать только формат JSON.

В то время как eval включает в себя весь язык JavaScript, JSON использует только крошечное подмножество языка. Среди конструкций языка JavaScript, которые должен распознавать eval, есть «Блок-оператор» (он же «составной оператор»). ; который представляет собой пару или фигурные скобки "{}" с некоторыми операторами внутри. Но фигурные скобки также используются в синтаксисе объектных литералов. Интерпретация зависит от контекста, в котором появляется код. Что-то может показаться вам литералом объекта, но eval будет рассматривать это как составной оператор.

В языке JavaScript объектные литералы встречаются справа от назначения.

var myObj = { ...some..code..here... };

Литералы объекта не встречаются сами по себе.

{ ...some..code..here... }   // this looks like a compound statement

Возвращаясь к исходному вопросу OP, заданному в 2008 году, он спросил, почему следующее не работает в eval ():

{ title: "One", key: "1" }

Ответ в том, что это похоже на составное утверждение. Чтобы преобразовать его в объект, вы должны поместить его в контекст, в котором составной оператор невозможен. Это делается путем заключения вокруг него скобок

( { title: "One", key: "1" } )    // not a compound statment, so must be object literal

OP также спросил , почему подобное заявление сделало успешно Eval:

[ { title: "One", key: "1" }, { title: "Two", key: "2" } ]

Применяется тот же ответ - фигурные скобки находятся в контексте, где составной оператор невозможен. Это контекст массива " [...]", и массивы могут содержать объекты, но не могут содержать операторов.

В отличие от eval (), JSON очень ограничен в своих возможностях. Ограничение сделано намеренно. Разработчик JSON задумал минималистское подмножество JavaScript, используя только синтаксис, который может отображаться справа от задания. Итак, если у вас есть код, который правильно разбирает в JSON ...

var myVar = JSON.parse("...some...code...here...");

... это означает, что он также будет выполнять юридический синтаксический анализ в правой части задания, например ...

var myVar = ...some..code..here... ;

Но это не единственное ограничение JSON. В языка BNF для JSON очень проста. Например, он не позволяет использовать одинарные кавычки для обозначения строк (как в JavaScript и Perl), и у него нет способа выразить одиночный символ в виде байта (как это делает 'C'). К сожалению, он также не допускает комментариев (что было бы очень хорошо при создании файлов конфигурации). Положительным моментом всех этих ограничений является то, что синтаксический анализ JSON выполняется быстро и не дает возможности для внедрения кода (угроза безопасности).

Из-за этих ограничений в JSON не используются скобки. Следовательно, скобка в строке JSON является недопустимым символом.

Всегда используйте формат JSON с ajax по следующим причинам:

  • Типичный конвейер ajax будет настроен для JSON.
  • Использование eval () будет подвергнуто критике как угроза безопасности.

В качестве примера конвейера ajax рассмотрим программу, которая включает в себя сервер Node и клиент jQuery. Клиентская программа использует вызов jQuery, имеющий форму $.ajax({dataType:'json',...etc.});. JQuery создает объект jqXHR для последующего использования, затем упаковывает и отправляет связанный запрос. Сервер принимает запрос, обрабатывает его и готов ответить. Серверная программа вызовет метод res.json(data)для упаковки и отправит ответ. На стороне клиента jQuery принимает ответ, обращается к связанному объекту jqXHR и обрабатывает данные в формате JSON. Все это работает без необходимости ручного преобразования данных. В ответе нет явного вызова JSON.stringify () на сервере Node и нет явного вызова JSON.parse () на клиенте; это все сделано за вас.

Использование eval связано с рисками безопасности внедрения кода. Вы можете подумать, что этого не может быть, но хакеры могут проявить изобретательность. Кроме того, eval проблематичен для оптимизации Javascript.

Если вы обнаружите, что используете функцию «stringify ()», имейте в виду, что некоторые функции с таким именем будут создавать строки, совместимые с «eval», а не с JSON. Например, в Node следующее дает вам функцию, которая создает строки в формате, совместимом с eval:

var stringify = require('node-stringify'); // generates eval() format

Это может быть полезно, но, если у вас нет особой потребности, вероятно, это не то, что вам нужно.

IAM_AL_X
источник
1

Если возврат массива работает, а возврат одного объекта - нет, вы также можете попробовать вернуть свой единственный объект в виде массива, содержащего этот единственный объект:

[ { title: "One", key: "1" } ]

таким образом вы возвращаете согласованную структуру данных, массив объектов, независимо от полезной нагрузки данных.

Я вижу, что вы пытались заключить свой единственный объект в «круглые скобки», и предлагаю это на примере, потому что, конечно, JavaScript обрабатывает [..] иначе, чем (..)

Дэвид Альперт
источник
1

Если вызывается обработчик ошибок jQuery и объект XHR содержит «ошибку парсера», это, вероятно, ошибка парсера, возвращаемая сервером.

Является ли ваш сценарий с несколькими результатами, когда вы вызываете службу без параметра, но он ломается, когда вы пытаетесь предоставить параметр для получения одной записи?

С какого бэкенда вы это возвращаете?

Например, в службах ASMX это часто бывает, когда параметры передаются в jQuery в виде объекта JSON, а не строки JSON. Если вы предоставите jQuery фактический объект JSON в качестве параметра «данные», он будет сериализовать его в стандартные пары с разделителями и k, v вместо отправки в формате JSON.

Дэйв Уорд
источник
1

Я обнаружил, что в некоторых своих реализациях мне пришлось добавить:

obj = new Object; obj = (data.obj);

что, казалось, решило проблему. Eval or not, мне показалось, что это то же самое.

Джей
источник
При инициализации нового объекта используйте литерал объекта, а не конструктор объекта: var obj = {};
Андреас Греч
Да, понятно, var myArray = [] для массивов и var myObject = {}, спасибо за подсказку, Дреас
Джей
1

jQuery подавляется некоторыми ключами JSON. Я отправлял этот фрагмент JSON на PHP:

echo json_encode((object) array('result' => 'success'));

Переименование клавиши «результат» на что-нибудь еще работает. Я предполагаю, что это какая-то коллизия зарезервированных слов и может быть ошибкой в ​​jQuery (1.4.2).

Джонатон Хилл
источник
1

В среде ColdFusion одна вещь, которая вызовет ошибку даже при правильном формате JSON, - это включение параметра «Включить вывод отладки запроса» в администраторе ColdFusion (в разделе «Отладка и ведение журнала»> «Параметры вывода отладки»). Информация об отладке будет возвращена с данными JSON и, таким образом, сделает ее недействительной.

Дэйв ДюПлантис
источник
1

также попробуйте это

$.ajax({
    url: url,
    data:datas,
    success:function(datas, textStatus, jqXHR){
    var returnedData = jQuery.parseJSON(datas.substr(datas.indexOf('{')));
})};

в моем случае сервер отвечает неизвестным символом перед '{'

валир
источник
1

Я получал status = parseerror и xhr.status = 200.

Проблема для меня заключалась в том, что URL-адрес внутри ответа JSON был исправлен с '\' переключением на '/'.

Brent
источник
0

Я боролся с этим и потратил несколько часов, пытаясь понять это, пока не использовал firebug, чтобы показать объект данных.

var data = eval("(" + data.responseText + ")");
console.log(data.count);
webwiseguys
источник
-1

использовать

$data = yourarray(); 
json_encode($data)

на стороне сервера. На стороне клиента используйте ajax с Datatype JSON и убедитесь, что кодировка вашего документа не UTF-8 с спецификацией, она должна быть UTF-8.

user2854865
источник