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


89

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

$ .getJSONは$ .ajaxのラッパーにすぎないため、物事を書き直してサプライズサプライズを行うことを決定したため、問題なく動作します。

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

これがコードです:

$(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
11

このソリューションではステータスコードを取得できず、代わりに「タイムアウト」が発生します。だから私は実際のエラーが何であるかを知ることができず、そのプロパティを処理することができません。
Tarlog

10
@Tarlog:それは論理的です。JSONPリクエストはネイティブAjaxリクエストではなく、<script>動的に挿入される単なるJavaScript タグです。したがって、ステータスコードが何であったかではなく、リクエストが失敗したことだけがわかります。ステータスコードを取得する場合は、従来のAjaxリクエストまたは他のクロスドメインテクニックを使用する必要があります。
ハスキー

1
@Huskyが言ったように、JSONPでステータスコードを使用することはできません。そのため、それを回避する必要があると思います。エラーが発生する唯一の方法は、タイムアウトを設定することです。これは、jQueryのドキュメント(他の多くのものと同様)でよりよく説明されているはずです。
アレハンドロガルシアイグレシアス

67

これは、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);
        }
    });
});

ホセに答えてくれてありがとう!jQueryでのネイティブjsonpの限られた実装が、代わりに$ .ajaxを使用した理由です。しかし、問題は$ .getJSONが$ .ajaxのラッパーではなく、dataType:jsonpであるようです。あれは正しいですか?
Matijs、2009年

今日まで時間がありませんでした。ただし、機能しません。エラーが発生しましたが、それはそれで終わりです。errorThrownが未定義であるため、どのようなエラーかわかりません。今のところ、$。ajaxとエラーメッセージの欠如に固執します。JavaScriptは、私にとってWebページの上の追加レイヤーです。Flickrがダウンしているか、エラーメッセージが表示されている場合は、とりあえずそれを使用する必要があります:)ご提案ありがとうございます。
Matijs

したがって、基本的には、jsonpプラグインを使用するJoséの提案は、正しく実行されれば機能するはずです。ただし、ここではjQueryの基本的なjsonラッパーを使用します。
Matijs 2009

これは、jsonpのエラー処理に組み込まれている制限に壁をぶつけたら、見事に機能しました
Jeremy Frey

7
このヒントで救われた別の開発者。ありがとう!
chesterbr 2009年

12

jQuery 1.4に悩まされている場合の解決策:

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

2
単なる注釈ですが、これは1.4にこだわっている人にとっては有効な解決策ですが、タイムアウト変数を十分に高く設定するので、遅いWebサービスで問題が発生することはありません:)。たとえば、1秒に設定すると、つまり、エラーコールバックがトリガーされますが、その1秒後も、呼び出しはフェッチされ、成功関数を呼び出します。したがって、十分に高い値に設定することを念頭に置いてください
サンダー

@Sander成功関数は、5秒のタイムアウトで10秒後に応答を得た場合にも呼び出される可能性があります。.abort()タイムアウト期間の後に保留中のjqXHRを呼び出すことは、より良い方法かもしれません。
Matijs

8

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

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


2

jQuery 1.5以降で解決されるようです。上記のコードを試したところ、コールバックが返されました。

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

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


1

Jose Basilioの 回答で述べられている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"
        }
    });

重要 コール$ .jsonp()にcallbackParameterを含めてください。そうでない場合、コールバック関数がサービスコールのクエリ文字列に挿入されないことがわかりました(jquery-jsonpのバージョン2.4.0以降)。

この質問は古いのですが、JSONPを使用したエラー処理の問題はまだ解決されていません。うまくいけば、この質問が「jquery jsonpエラー処理」でGoogle内でトップランクになっているため、この更新が他の人を助けることになります。


素晴らしい発見、そして驚くべきことに、このスレッドは3年経ってもまだ生きています…
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;
}

このソリューションについてどう思いますか?互換性の問題が発生する可能性はありますか?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.