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 时提出的

4

7 回答 7

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 秒后没有成功请求时,超时似乎可以解决问题并调用错误处理程序。

我也写了一篇关于这个主题的小博文。

于 2011-02-25T19:38:26.917 回答
67

这是 jQuery 中原生 jsonp 实现的一个已知限制。以下文字来自IBM DeveloperWorks

JSONP 是一种用于构建 mashup 的非常强大的技术,但不幸的是,它并不是解决所有跨域通信需求的万灵药。它有一些缺点,在投入开发资源之前必须认真考虑。首先,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);
        }
    });
});
于 2009-06-16T17:10:38.747 回答
12

如果您被 jQuery 1.4 卡住,一个解决方案:

var timeout = 10000;
var id = setTimeout( errorCallback, timeout );
$.ajax({
    dataType: 'jsonp',
    success: function() {
        clearTimeout(id);
        ...
    }
});
于 2011-06-20T17:46:15.443 回答
8

这可能是 jQuery 的“已知”限制;但是,它似乎没有很好的记录。我今天花了大约 4 个小时试图了解为什么我的超时不起作用。

我切换到jquery.jsonp,它的工作就像一个魅力。谢谢你。

于 2010-01-13T06:34:29.060 回答
2

似乎从 jQuery 1.5 开始解决。我已经尝试了上面的代码,我得到了回调。

我说“似乎是”是因为jQuery.ajax()的错误回调的文档仍然有以下注释:

注意:跨域脚本和 JSONP 请求不调用此处理程序。

于 2011-02-07T20:45:36.560 回答
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() 中包含回调参数,否则我发现回调函数永远不会被注入到服务调用的查询字符串中(当前为 jquery-jsonp 的 2.4.0 版)。

我知道这个问题很老,但是使用 JSONP 处理错误的问题仍然没有“解决”。希望此更新将对其他人有所帮助,因为此问题在“jquery jsonp 错误处理”方面在 Google 中排名第一。

于 2012-10-22T08:25:12.080 回答
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;
}

你觉得这个解决方案怎么样?是否可能导致兼容性问题?

于 2013-04-18T20:01:50.930 回答