JQuery ajax (jsonp)忽略超时并不触发错误事件

为了添加一些基本的错误处理,我想重写一段使用 jQuery $的代码。获取来自 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版时提出的

50265 次浏览

This is a known limitation with the native jsonp implementation in jQuery. The text below is from IBM DeveloperWorks

JSONP is a very powerful technique for building mashups, but, unfortunately, it is not a cure-all for all of your cross-domain communication needs. It has some drawbacks that must be taken into serious consideration before committing development resources. First and foremost, there is no error handling for JSONP calls. If the dynamic script insertion works, you get called; if not, nothing happens. It just fails silently. For example, you are not able to catch a 404 error from the server. Nor can you cancel or restart the request. You can, however, timeout after waiting a reasonable amount of time. (Future jQuery versions may have an abort feature for JSONP requests.)

However there's a jsonp plug-in available on GoogleCode that provides support for error handling. To get started, just make the following changes to your code.

You can either download it, or just add a script reference to the plug-in.

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

Then modify your ajax call as shown below:

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

This may be a "known" limitation of jQuery; however, it does not seem to be well documented. I spent about 4 hours today trying to understand why my timeout was not working.

I switched to jquery.jsonp and it worked liked a charm. Thank you.

Seems to be resolved as of jQuery 1.5. I've tried the code above and I get the callback.

I say "seems to be" because the documentation of the error callback for jQuery.ajax() still has the following note:

Note: This handler is not called for cross-domain script and JSONP requests.

jQuery 1.5 and higher have better support for error handling with JSONP requests. However, you need to use the $.ajax method instead of $.getJSON. For me, this works:

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


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


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

The timeout seems to do the trick and call the error handler, when there is no successful request after 10 seconds.

I did a little blogpost on this subject as well.

A solution if you're stuck with jQuery 1.4:

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

The jquery-jsonp jQuery plugin mentioned in Jose Basilio's answer can now be found on GitHub.

Unfortunately the documentation is somewhat spartan, so I've provided a simple example:

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

Important Include the callbackParameter in the call $.jsonp() otherwise I've found that the callback function never gets injected into the query string of the service call (current as of version 2.4.0 of jquery-jsonp).

I know this question is old, but the issue of error handling using JSONP is still not 'resolved'. Hopefully this update will assist others as this question is the top-ranked within Google for "jquery jsonp error handling".

What about listening to the script's onerror event ? I had this problem and solved it by patching jquery's method where the script tag was created. Here is the interesting bit of code :

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

What do you think of this solution ? Is it likely to cause compatibility issues ?