Непонятное поведение 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) {

    }
});