jQuery ajax (jsonp) ігнорує час очікування та не запускає подію помилки


89

Щоб додати деяку основну обробку помилок, я хотів переписати фрагмент коду, який використовував jQuery $ .getJSON для витягування деяких фотографій з 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

Відповіді:


86

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 секунд немає успішного запиту.

Я також зробив невеликий допис у блозі на цю тему.


23
Зараз мене не дратує, що я вдарився головою про цю проблему протягом 2 днів, і потрібен якийсь незрозумілий пошук у StackOverflow, щоб з’ясувати, що мені потрібно додати час очікування до міждоменного запиту, щоб отримати помилку. Як цього не згадати в документації jQuery? Чи насправді міждоменні запити jsonp є настільки рідкісними? У будь-якому випадку дякую, дякую, дякую. +1
chrixian

За допомогою цього рішення я не можу отримати код стану, замість цього я отримую "тайм-аут". Отже, я не можу знати, що таке фактична помилка, і не можу обробляти її властивість.
Тарлог

10
@Tarlog: це логічно. Запити JSONP не є власними запитами Ajax, це просто <script>теги Javascript , які динамічно вставляються. Тому єдине, що ви можете знати, це те, що запит не вдався, а не те, яким був код стану. Якщо ви хочете отримати коди стану, вам потрібно використовувати традиційні запити Ajax або інші міждоменні методи.
Husky

1
Як сказав @Husky, ви не можете мати коди статусу з JSONP, і я вважаю, що тому вам слід намагатися уникати цього. Єдиний спосіб отримати помилку - встановити тайм-аут. Це слід краще пояснити в документації jQuery (як і багато іншого).
Alejandro García Iglesias

67

Це відоме обмеження для власної реалізації 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);
        }
    });
});

Дякуємо за відповідь Хосе! Обмежена реалізація власного jsonp у jQuery стала причиною того, що я замість цього вибрав $ .ajax. Однак, схоже, проблема полягає не в тому, що $ .getJSON є обгорткою навколо $ .ajax, а в dataType: jsonp. Це правильно?
Matijs

Не встиг до сьогодні. Однак це не працює. Я отримую повідомлення про помилку, але це все. Я не знаю, яка помилка як errorThrown не визначена. Наразі я дотримуюся $ .ajax та відсутності повідомлень про помилки. Javascript - це додатковий шар поверх веб-сторінки для мене. Якщо Flickr не працює або надсилає повідомлення про помилки, нам поки що доведеться жити з цим :) Дякуємо за вашу пропозицію.
Matijs

Отже, в основному пропозиція Хосе з використанням плагіна jsonp повинна, якщо це зроблено правильно, спрацювати. На даний момент, однак, я дотримуюся основної обгортки json для jQuery.
Matijs

Це чудово спрацювало для мене, коли я вдарився об стіну за допомогою вбудованих обмежень обробки помилок jsonp
Джеремі Фрей,

7
Ще один розробник врятував цю підказку. Дякую!
chesterbr

12

Рішення, якщо ви застрягли в jQuery 1.4:

var timeout = 10000;
var id = setTimeout( errorCallback, timeout );
$.ajax({
    dataType: 'jsonp',
    success: function() {
        clearTimeout(id);
        ...
    }
});

2
просто зауваження, це дійсне рішення для людей, які застрягли з 1.4, але встановіть свою змінну часу очікування досить високою, щоб у вас не було проблем із повільними веб-послугами :). наприклад, якщо ви встановите його на одну секунду, ви зможете зрозуміти, що я маю на увазі, спрацьовує зворотний виклик помилки, тоді як через 1 секунду ваш дзвінок все одно отримується і викликає функцію успіху. так що майте на увазі, щоб встановити його досить високим
Сандер

Функцію @Sander для успіху можна навіть викликати, якщо ви отримаєте відповідь через 10 секунд із таймаутом 5 секунд. Виклик .abort()очікуваного jqXHR після періоду очікування може бути кращим способом.
Matijs

8

Це може бути "відоме" обмеження jQuery; однак, здається, це недостатньо добре задокументовано. Сьогодні я провів близько 4 годин, намагаючись зрозуміти, чому мій тайм-аут не працює.

Я перейшов на jquery.jsonp, і це спрацювало сподобалось. Дякую.


2

Здається, це буде вирішено станом на jQuery 1.5. Я спробував наведений вище код і отримав зворотний дзвінок.

Я кажу "здається", оскільки документація зворотного виклику помилки для jQuery.ajax () все ще містить таку примітку:

Примітка: Цей обробник не викликається для міждоменних сценаріїв та запитів JSONP.


1

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”.


приємна знахідка, і дивовижна ця тема все ще живе після трьох років ...
Matijs

1

А як щодо прослуховування події сценарію onerror? Я мав цю проблему і вирішив її, виправивши метод jquery там, де був створений тег скрипта. Ось цікавий біт коду:

// 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;
}

Що ви думаєте про це рішення? Чи це може спричинити проблеми сумісності?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.