web-dev-qa-db-ja.com

jQuery ajax(jsonp)はタイムアウトを無視し、エラーイベントを発生させません

基本的なエラー処理を追加するために、jQueryの$ .getJSONを使用してFlickrから写真を取り込むコードを書き直したいと考えました。これを行う理由は、$。getJSONがエラー処理を提供せず、タイムアウトを処理しないためです。

$ .getJSONは$ .ajaxの単なるラッパーなので、このことを書き直してサプライズサプライズを行うことにしましたが、問題なく動作します。

今から楽しみが始まります。意図的に404を発生させる(URLを変更する)か、ネットワークをタイムアウトさせる(インターWebに接続されない)場合、エラーイベントはまったく発生しません。私が間違っていることについて私は途方に暮れています。ヘルプは大歓迎です。

コードは次のとおりです。

$(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のときにこの質問が尋ねられたことを付け加えます。

89
Matijs

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 を行いました。

86
Husky

これは、jQueryのネイティブjsonp実装の既知の制限です。以下のテキストは IBM DeveloperWorks からのものです

JSONPはマッシュアップを構築するための非常に強力な手法ですが、残念ながら、クロスドメイン通信のすべてのニーズをすべて解決できるわけではありません。開発リソースをコミットする前に真剣に考慮しなければならないいくつかの欠点があります。何よりもまず、JSONP呼び出しのエラー処理はありません。動的なスクリプト挿入が機能する場合、呼び出されます。そうでなければ、何も起こりません。黙って失敗するだけです。たとえば、サーバーから404エラーをキャッチすることはできません。また、リクエストをキャンセルまたは再開することもできません。ただし、妥当な時間待機した後にタイムアウトすることはできます。 (将来のjQueryバージョンには、JSONPリクエストの中止機能が含まれる場合があります。)

ただし、エラー処理のサポートを提供するjsonpプラグインが GoogleCode で利用可能です。開始するには、コードに次の変更を加えるだけです。

ダウンロードするか、プラグインにスクリプト参照を追加するだけです。

<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);
        }
    });
});
67
Jose Basilio

JQuery 1.4にこだわっている場合の解決策:

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

これはjQueryの「既知の」制限かもしれません。ただし、十分に文書化されていないようです。今日、タイムアウトが機能しなかった理由を理解しようとして、約4時間を費やしました。

私は jquery.jsonp に切り替えましたが、それは魅力的でした。ありがとうございました。

8
Marc

JQuery 1.5の時点で解決されるようです。上記のコードを試したところ、コールバックが取得されました。

jQuery.ajax() のエラーコールバックのドキュメントにはまだ次のような注意事項があるため、「そうである」と言います。

注:このハンドラーは、クロスドメインスクリプトおよびJSONPリクエストでは呼び出されません。

2
Peter Tate

Jose Basilio'sanswer で言及されている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"
        }
    });

Importantcall $ .jsonp()にコールバックパラメーターを含める(jquery-jsonpのバージョン2.4.0現在)。

この質問は古いことは知っていますが、JSONPを使用したエラー処理の問題はまだ「解決」されていません。この質問が「jquery jsonpエラー処理」でGoogle内でトップランクにランクされているため、このアップデートが他のユーザーを支援することを願っています。

1
OiDatsMyLeg

スクリプトの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;
}

このソリューションについてどう思いますか?互換性の問題を引き起こす可能性はありますか?

1
Hadrien Milano