jQuery ajax (jsonp) bir zaman aşımını yok sayar ve hata olayını tetiklemez


89

Bazı temel hata işlemeyi eklemek için, Flickr'dan bazı fotoğrafları çekmek için jQuery'nin $ .getJSON'unu kullanan bir kod parçasını yeniden yazmak istedim. Bunu yapmanın nedeni, $ .getJSON'un hata işleme sağlamaması veya zaman aşımlarıyla çalışmamasıdır.

$ .GetJSON sadece $ .ajax civarında bir paketleyici olduğundan, bir şeyi yeniden yazmaya ve sürpriz sürprizi yapmaya karar verdim, kusursuz çalışıyor.

Şimdi eğlence yine de başlıyor. Kasıtlı olarak bir 404'e (URL'yi değiştirerek) neden olduğumda veya ağın zaman aşımına uğramasına (interweb'lere bağlanmayarak) neden olduğumda, hata olayı hiç çalışmıyor. Neyi yanlış yaptığımı bilemiyorum. Yardım çok takdir edilmektedir.

İşte kod:

$(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);
        }
    });

});

Bu sorunun jQuery 1.4.2 sürümündeyken sorulduğunu eklemek isterim.

Yanıtlar:


86

jQuery 1.5 ve sonraki sürümler, JSONP isteklerinde hata işleme için daha iyi desteğe sahiptir. Ancak $.ajaxbunun yerine yöntemi kullanmanız gerekir $.getJSON. Benim için bu işe yarıyor:

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

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

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

10 saniye sonra başarılı bir istek olmadığında zaman aşımı hile yapıyor ve hata işleyicisini çağırıyor gibi görünüyor.

Ben de bu konuda küçük bir blog yazısı yazdım .


23
Şu anda 2 gün boyunca bu soruna karşı kafa kafaya çarptığım ve hatayı ateşlemek için bir çapraz etki alanı isteğine bir zaman aşımı eklemem gerektiğini öğrenmek için StackOverflow'da biraz belirsiz arama yapılması gerektiğinden rahatsızım. JQuery belgelerinde bundan nasıl bahsedilemez? Alanlar arası jsonp istekleri gerçekten bu kadar nadir mi? Her halükarda, teşekkürler, teşekkürler, teşekkürler. +1
chrixian

Bu çözümle durum kodunu alamıyorum, bunun yerine "zaman aşımı" alıyorum. Bu yüzden gerçek hatanın ne olduğunu bilemiyorum ve özelliği ile başa çıkamıyorum.
Tarlog

10
@Tarlog: bu mantıklı. JSONP istekleri yerel Ajax istekleri değildir, bunlar <script>dinamik olarak eklenen Javascript etiketleridir. Bu nedenle bildiğiniz tek şey, durum kodunun ne olduğu değil, bir isteğin başarısız olduğudur. Durum kodlarını almak istiyorsanız, geleneksel Ajax isteklerini veya diğer alanlar arası teknikleri kullanmanız gerekir.
Husky

1
@Husky'nin dediği gibi, JSONP ile durum kodlarına sahip olamazsınız ve bu yüzden bundan kaçınmaya çalışmanız gerektiğine inanıyorum. Hata almanın tek yolu zaman aşımı koymaktır. Bu, jQuery belgelerinde daha iyi açıklanmalıdır (diğer pek çok şey gibi).
Alejandro García Iglesias

67

Bu, jQuery'deki yerel jsonp uygulamasında bilinen bir sınırlamadır. Aşağıdaki metin IBM DeveloperWorks'ten alınmıştır

JSONP, melez uygulamalar oluşturmak için çok güçlü bir tekniktir, ancak maalesef, tüm etki alanları arası iletişim ihtiyaçlarınız için bir çare değildir. Geliştirme kaynaklarını uygulamaya koymadan önce dikkate alınması gereken bazı dezavantajları vardır. Öncelikle ve en önemlisi, JSONP çağrıları için herhangi bir hata işleme yoktur. Dinamik komut dosyası ekleme çalışırsa, çağrılırsınız; değilse, hiçbir şey olmaz. Sadece sessizce başarısız oluyor. Örneğin, sunucudan bir 404 hatası yakalayamazsınız. İsteği iptal edemez veya yeniden başlatamazsınız. Ancak makul bir süre bekledikten sonra zaman aşımına uğrayabilirsiniz. (Gelecekteki jQuery sürümlerinde JSONP istekleri için bir durdurma özelliği olabilir.)

Ancak bir jsonp eklenti mevcut hayat var GoogleCode hata işleme için destek sağlar. Başlamak için kodunuzda aşağıdaki değişiklikleri yapmanız yeterlidir.

Ya indirebilir ya da eklentiye bir komut dosyası referansı ekleyebilirsiniz.

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

Ardından, ajax aramanızı aşağıda gösterildiği gibi değiştirin:

$(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);
        }
    });
});

Cevap verdiğin için teşekkürler José! Bunun yerine $ .ajax'a gitmemin nedeni jQuery'de yerel jsonp'nin sınırlı uygulamasıydı. Ancak, öyle görünüyor ki, sorun $ .getJSON'un $ .ajax etrafında bir sarmalayıcı olması değil, dataType: jsonp olmasıdır. Bu doğru mu?
Matijs

Bugüne kadar vaktim olmadı. Ancak işe yaramıyor. Bir hata alıyorum ama bununla ilgili. ErrorThrown tanımsız olduğu için hangi hatanın olduğunu bilmiyorum. Şimdilik $ .ajax ve hata mesajlarının eksikliği ile devam edeceğim. Javascript benim için web sayfasının en üstünde bulunan ekstra bir katmandır. Flickr çalışmıyorsa veya hata mesajları veriyorsa, şimdilik bununla yaşamak zorunda kalacağız :) Öneriniz için teşekkürler.
Matijs

Yani temelde José'nin jsonp eklentisini kullanma önerisi, doğru yapılırsa çalışmalıdır. Şimdilik ancak jQuery için temel json paketleyicisine bağlı kalacağım.
Matijs

Jsonp'nin hata işlemesinin yerleşik sınırlamalarıyla duvara çarptığımda bu, benim için harika bir şekilde çalıştı
Jeremy Frey

7
Bu ipucuyla başka bir geliştirici kurtardı. Teşekkürler!
chesterbr

12

JQuery 1.4 ile takıldıysanız bir çözüm:

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

2
sadece bir açıklama, 1.4 ile sıkışmış insanlar için geçerli bir çözüm, ancak zaman aşımı değişkeninizi yeterince yüksek ayarlayın, böylece yavaş web hizmetlerinde sorun yaşamazsınız :). Örneğin bir saniyeye ayarlarsanız, ne demek istediğimi görebilirsiniz, hata geri araması tetiklenir, bu 1 saniye sonra aramanız hala alınır ve başarı işlevini çağırır. bu nedenle, yeterince yüksek bir
değere

@Sander başarı fonksiyonu, 10 saniye sonra 5 saniyelik bir zaman aşımı ile bir cevap alırsanız bile çağrılabilir. .abort()Bir zaman aşımı süresinden sonra bekleyen bir jqXHR çağırmak daha iyi bir yol olabilir.
Matijs

8

Bu, jQuery'nin "bilinen" bir sınırlaması olabilir; ancak, iyi belgelenmiş görünmüyor. Bugün, zaman aşımımın neden çalışmadığını anlamaya çalışmak için yaklaşık 4 saat harcadım.

Jquery.jsonp'a geçtim ve harika çalıştı. Teşekkür ederim.


2

JQuery 1.5'ten itibaren çözülmüş görünüyor. Yukarıdaki kodu denedim ve geri aramayı alıyorum.

"Öyle görünüyor" diyorum çünkü jQuery.ajax () için hata geri aramasının dokümantasyonu hala aşağıdaki nota sahip:

Not: Bu işleyici, etki alanları arası komut dosyası ve JSONP istekleri için çağrılmaz.


1

Jquery-jsonp jQuery eklentisi belirtilen Jose Basilio en cevabı şimdi bulunabilir GitHub .

Maalesef belgeler biraz spartan, bu yüzden basit bir örnek verdim:

    $.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"
        }
    });

Önemli CallbackParameter'ı $ .jsonp () çağrısına dahil edin, aksi takdirde callback işlevinin hiçbir zaman hizmet çağrısının sorgu dizesine enjekte edilmediğini gördüm (jquery-jsonp 2.4.0 sürümünden itibaren geçerli).

Bu sorunun eski olduğunu biliyorum, ancak JSONP kullanarak hata işleme sorunu hala 'çözülmedi'. Bu sorunun Google'da "jquery jsonp hata işleme" açısından en üst sırada yer alması nedeniyle bu güncellemenin başkalarına yardımcı olacağını umuyoruz.


güzel
keşif

1

Senaryonun onerror olayını dinlemeye ne dersiniz? Bu sorunu yaşadım ve jquery'nin komut dosyası etiketinin oluşturulduğu yöntemine yama yaparak çözdüm. İşte ilginç kod parçası:

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

Bu çözüm hakkında ne düşünüyorsunuz? Uyumluluk sorunlarına neden olma ihtimali var mı?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.