Непонятное поведение jQuery $.ajax(), когда данные содержат последовательные вопросительные знаки
Надеюсь, это достаточно ясно, я потратил много времени, пытаясь уладить эту проблему, поэтому у меня может не хватить времени, чтобы написать идеальный вопрос. Кроме того, это, возможно, придется включить в отчет об ошибке jQuery, но я бы лучше сначала опубликовал его здесь, поскольку я новичок в JavaScript, так что, возможно, я сделал что-то не так...
Я создал следующий фрагмент кода, чтобы воспроизвести его. Он использует PHP для вывода полученных данных в браузер, хотя может работать без PHP.
Проблема может быть воспроизведена в Firefox 4 и Chrome 10. Вам понадобится консоль, чтобы увидеть, что происходит.
Вот код:
<?
$input = file_get_contents('php://input');
if (isset($input) and !empty($input)) {
echo $input;
die();
}
?>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script>
$(function(){
var jsonData = {
"something":"??"
};
jsonData = JSON.stringify(jsonData);
var onSuccess = function(data){
console.log("Ajax Success!");
console.log(data);
}
var onError = function(jqXHR, textStatus, errorThrown){
console.log("Ajax Error: "+textStatus);
console.log("More info:");
console.log(errorThrown);
console.log(jqXHR);
}
console.log("Now sending this: "+jsonData+" through Ajax...");
var ajaxCmd = {
"url" : "test.php",
"dataType": "json",
"type" : "POST",
"async" : false,
"error" : onError,
"success" : onSuccess,
"data" : jsonData
};
$.ajax(ajaxCmd);
});
</script>
</head>
<body>
<pre>Check your JavaScript console...</pre>
</body>
</html>
При загрузке выдает некоторую явно не связанную ошибку или исключение при разборе (в зависимости от браузера). JSON, который должен быть отправлен, это {"что-то": "??"}, но если вы проверите его на вкладке сети Firebug (или аналога Chrome), вы увидите, что "??" заменяется некоторой строкой jQuery, которая выглядит следующим образом: jQuery152026845051744021475_1303152126170
И это то, что получает сервер.
Эта проблема возникает только в том случае, если в поле значения внутри отправленного объекта JSON есть два или более последовательных вопросительных знака, даже если там есть другие буквы. С одним знаком вопроса это похоже на работу. Также изменение "dataType" на "text" исправляет это. Но мне нужны все эти функции!
Если вы закомментируете "jsonData = JSON.stringify(jsonData);" или "$.ajax(ajaxCmd)"; ошибки также чудесным образом исчезают.
Больше информации:
Выход консоли Chrome:
test.php:21Now sending this: {"something":"??"} through Ajax...
jquery.min.js:16Uncaught SyntaxError: Unexpected token :
test.php:16Ajax Error: parsererror
test.php:17More info:
test.php:18jQuery15206220591682940722_1303153398797 was not called
test.php:19
Object
Firefox Firebug вывод:
Now sending this: {"something":"??"} through Ajax...
Ajax Error: parsererror
More info:
jQuery15206494160738701454_1303153492631 was not called
Object { readyState=4, responseText="{"something":"jQuery152...8701454_1303153492631"}", more...}
invalid label
{"something":"jQuery15206494160738701454_1303153492631"}
Ответы
Ответ 1
Если вы не собираетесь форматировать значение "data" в качестве допустимой строки HTML-запроса, вы не должны предварительно подставлять его. Как вы отметили, если вы не назовете "JSON.stringify()", то это сработает. Это потому, что библиотека уже знает, как справиться с этим.
Теперь, если вы хотите отправить строку JSON в качестве самого параметра к серверному коду, который ожидает декодирования некоторого JSON, вам нужно настроить его как параметр:
$.ajax(url, {
// ...
data: { jsonParam: jsonData },
// ...
});
Теперь ваш сервер увидит HTTP-запрос с параметром "jsonParam", и его значение будет вашей строкой, связанной с JSON.
Ответ 2
jQuery использует ??
как заполнитель для функции обратного вызова при использовании jsonp
. Когда он анализирует запрос Ajax и находит двойной вопросительный знак (или больше вопросов), он автоматически предполагает, что вы пытаетесь использовать jsonp
. Когда вы устанавливаете тип контента вручную, он игнорирует вопросительные знаки.
Итак, избегайте проблемы с помощью contentType:
$.ajax(
url: "your-url.php",
dataType: "json", // what you expect the server to return
contentType: "application/json", // what you are sending
...
);
Для справки:
jQuery Bugtracker: $.AJAX ИЗМЕНИЛ СОДЕРЖАНИЕ ПОСЛЕ ЕСЛИ ВКЛЮЧАЕТ "??" (2 ВОПРОСЫ)
Надеюсь, что он сохранит кого-то из часов отладки...
Ответ 3
Точная же проблема с jQuery 1.71, двойной вопросительный знак и какая-то сумасшедшая строка вставлена.
Удалось исправить это, удалив
dataType: 'JSON'
из команды ajax, и она волшебным образом перестала это делать.
Ответ 4
Я думаю, что ответ, который вы ищете, устанавливает jsonp: false в параметрах вызова AJAX. У меня была такая же проблема и я исправил это.
Прочтите ответ на этот похожий вопрос для получения дополнительной информации:
Опубликованные данные переопределяются с момента обновления с jQuery 1.4 до 1.5
Ответ 5
Так как ни один из существующих ответов не упоминал об этом. Вы можете решить эту проблему, добавив
jsonp: false
в настройках вашего ajax-запроса.
Ответ 6
Это звучит как проблема с кодировкой. Если ваши данные не в формате UTF-8 (например, MS Word или что-то еще), это может произойти.
Ответ 7
У меня такая проблема в 1.5.2.
Это ошибка jQuery: http://bugs.jquery.com/ticket/8417.
Вы можете обновить до 1.6.4 или сделать следующее:
В функции jQuery "jQuery.ajaxPrefilter"
изменено:
var dataIsString = ( typeof s.data === "string" );
по
var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
( typeof s.data === "string" );
и изменил эту переменную ниже в условии "если" следующим образом:
if ( s.dataTypes[ 0 ] === "jsonp" ||
originalSettings.jsonpCallback ||
originalSettings.jsonp != null ||
s.jsonp !== false && ( jsre.test( s.url ) ||
dataIsString && jsre.test( s.data ) ) ) {
inspectData && jsre.test( s.data ) ) ) {
Я взял эту форму для исправления jQuery 1.6.4.
Ответ 8
У меня была та же проблема. Сброс значений с помощью encodeURIComponent
выполнил задание!
Ответ 9
Я столкнулся с той же проблемой. Указание "contentType": "application/json; charset = utf-8" решает эту проблему.
jQuery.ajax({
"url": url,
"data": JSON.stringify(payload),
"type": "POST",
"dataType": "json",
"contentType":"application/json; charset=utf-8",
"success": function(data) {
},
"error": function(jqXHR, textStatus, errorThrown) {
}
});