JQuery AJAX (JSONP) игнорирует время ожидания и не запускает событие ошибки - PullRequest
89 голосов
/ 16 июня 2009

Чтобы добавить базовую обработку ошибок, я хотел переписать кусок кода, который использовал $ .getJSON jQuery для получения некоторых фотографий из Flickr. Причина этого заключается в том, что $ .getJSON не обеспечивает обработку ошибок и работу с таймаутами.

Поскольку $ .getJSON - это просто оболочка для $ .ajax, я решил переписать эту вещь и удивить удивлением, она работает без нареканий.

Теперь начинается самое интересное. Когда я преднамеренно вызываю 404 (изменяя URL-адрес) или вызываю таймаут сети (не будучи подключенным к сетям), событие ошибки вообще не срабатывает. Я в растерянности относительно того, что я делаю неправильно. Помощь очень ценится.

Вот код:

$(document).ready(function(){

    // var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne"; // correct URL
    var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne_______"; // this should throw a 404

    $.ajax({
        url: jsonFeed,
        data: { "lang" : "en-us",
                "format" : "json",
                "tags" : "sunset"
        },
        dataType: "jsonp",
        jsonp: "jsoncallback",
        timeout: 5000,
        success: function(data, status){
            $.each(data.items, function(i,item){
                $("<img>").attr("src", (item.media.m).replace("_m.","_s."))
                          .attr("alt", item.title)
                          .appendTo("ul#flickr")
                          .wrap("<li><a href=\"" + item.link + "\"></a></li>");
                if (i == 9) return false;
            });
        },
        error: function(XHR, textStatus, errorThrown){
            alert("ERREUR: " + textStatus);
            alert("ERREUR: " + errorThrown);
        }
    });

});

Я хотел бы добавить, что этот вопрос задавался, когда jQuery был в версии 1.4.2

Ответы [ 7 ]

86 голосов
/ 25 февраля 2011

jQuery 1.5 и выше имеют лучшую поддержку обработки ошибок с запросами JSONP. Однако вам нужно использовать метод $.ajax вместо $.getJSON. Для меня это работает:

var req = $.ajax({
    url : url,
    dataType : "jsonp",
    timeout : 10000
});

req.success(function() {
    console.log('Yes! Success!');
});

req.error(function() {
    console.log('Oh noes!');
});

Похоже, что тайм-аут делает свое дело и вызывает обработчик ошибок, когда через 10 секунд нет успешного запроса.

Я также написал blogpost на эту тему.

67 голосов
/ 16 июня 2009

Это известное ограничение для нативной реализации jsonp в jQuery. Текст ниже взят из IBM DeveloperWorks

JSONP - очень мощная техника для создание коллажей, но, к сожалению, это не панацея от всех ваших междоменная связь Это имеет некоторые недостатки, которые должны быть приняты в серьезном рассмотрении, прежде чем выделение ресурсов для развития. В первую очередь ошибки нет обработка вызовов JSONP. Если динамическая вставка скрипта работает, вы позвонить; если нет, ничего не происходит. Просто молча терпит неудачу. Например, Вы не можете поймать ошибку 404 с сервера. Вы также не можете отменить или перезапустите запрос. Вы можете, однако, тайм-аут после ожидания разумного количество времени. (Будущее JQuery версии могут иметь функцию прерывания для Запросы JSONP.)

Однако в GoogleCode имеется подключаемый модуль jsonp, который поддерживает обработку ошибок. Для начала просто внесите следующие изменения в свой код.

Вы можете либо загрузить его, либо просто добавить ссылку на скрипт в плагин.

<script type="text/javascript" 
     src="http://jquery-jsonp.googlecode.com/files/jquery.jsonp-1.0.4.min.js">
</script>

Затем измените ваш вызов ajax, как показано ниже:

$(function(){
    //var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne"; // correct URL
    var jsonFeed = "http://api.flickr.com/services/feeds/photos_public.gne_______"; // this should throw a 404  
    $.jsonp({
        url: jsonFeed,
        data: { "lang" : "en-us",
                "format" : "json",
                "tags" : "sunset"
        },
        dataType: "jsonp",
        callbackParameter: "jsoncallback",
        timeout: 5000,
        success: function(data, status){
            $.each(data.items, function(i,item){
                $("<img>").attr("src", (item.media.m).replace("_m.","_s."))
                          .attr("alt", item.title)
                          .appendTo("ul#flickr")
                          .wrap("<li><a href=\"" + item.link + "\"></a></li>");
                if (i == 9) return false;
            });
        },
        error: function(XHR, textStatus, errorThrown){
            alert("ERREUR: " + textStatus);
            alert("ERREUR: " + errorThrown);
        }
    });
});
12 голосов
/ 20 июня 2011

Решение, если вы застряли с jQuery 1.4:

var timeout = 10000;
var id = setTimeout( errorCallback, timeout );
$.ajax({
    dataType: 'jsonp',
    success: function() {
        clearTimeout(id);
        ...
    }
});
8 голосов
/ 13 января 2010

Это может быть «известным» ограничением jQuery; однако, это не кажется хорошо документированным. Я провел около 4 часов сегодня, пытаясь понять, почему мой тайм-аут не работал.

Я переключился на jquery.jsonp , и это сработало как шарм. Спасибо.

2 голосов
/ 07 февраля 2011

Кажется, будет решено с jQuery 1.5. Я попробовал код выше и получаю ответный звонок.

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

Примечание. Этот обработчик не вызывается для междоменных сценариев и запросов JSONP.

1 голос
/ 19 апреля 2013

Как насчет прослушивания события onerror скрипта? У меня была эта проблема, и я решил ее, исправив метод jquery, в котором был создан тег script. Вот интересный фрагмент кода:

// Attach handlers for all browsers
script.onload = script.onreadystatechange = function( _, isAbort ) {

    if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {

        cleanup();

        // Callback if not abort
        if ( !isAbort ) {
            callback( 200, "success" );
        }
    }
};

/* ajax patch : */
script.onerror = function(){
    cleanup();

    // Sends an inappropriate error, still better than nothing
    callback(404, "not found");
};

function cleanup(){
    // Handle memory leak in IE
    script.onload = script.onreadystatechange = null;

    // Remove the script
    if ( head && script.parentNode ) {
        head.removeChild( script );
    }

    // Dereference the script
    script = undefined;
}

Что вы думаете об этом решении? Это может вызвать проблемы совместимости?

1 голос
/ 22 октября 2012

Плагин jQuery-jsonp jQuery, упомянутый в ответ Хосе Базилио , теперь можно найти на GitHub .

К сожалению, документация несколько спартанская, поэтому я привел простой пример:

    $.jsonp({
        cache: false,
        url: "url",
        callbackParameter: "callback",
        data: { "key" : "value" },
        success: function (json, textStatus, xOptions) {
            // handle success - textStatus is "success"   
        },
        error: function (xOptions, textStatus) {
            // handle failure - textStatus is either "error" or "timeout"
        }
    });

Важно Включите callbackParameter в вызов $ .jsonp (), в противном случае я обнаружил, что функция обратного вызова никогда не вводится в строку запроса вызова службы (актуально для версии 2.4.0 jquery-jsonp).

Я знаю, что этот вопрос старый, но проблема обработки ошибок с использованием JSONP до сих пор не решена. Надеемся, что это обновление поможет другим, так как этот вопрос занимает первое место в Google по «обработке ошибок jquery jsonp».

...