jQuery ajax (jsonp) 忽略超时并且不触发错误事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1002367/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
jQuery ajax (jsonp) ignores a timeout and doesn't fire the error event
提问by Matijs
To add some basic error handling, I wanted to rewrite a piece of code that used jQuery's $.getJSON to pull in some photo's from Flickr. The reason for doing this is that $.getJSON doesn't provide error handling or work with timeouts.
为了添加一些基本的错误处理,我想重写一段代码,使用 jQuery 的 $.getJSON 从 Flickr 中提取一些照片。这样做的原因是 $.getJSON 不提供错误处理或超时工作。
Since $.getJSON is just a wrapper around $.ajax I decided to rewrite the thing and surprise surprise, it works flawlessly.
由于 $.getJSON 只是 $.ajax 的一个包装器,我决定重写它并惊喜地发现,它完美无缺。
Now the fun starts though. When I deliberately cause a 404 (by changing the URL) or cause the network to timeout (by not being hooked up to the interwebs), the error event doesn't fire, at all. I'm at a loss as to what I'm doing wrong. Help is much appreciated.
现在乐趣开始了。当我故意导致 404(通过更改 URL)或导致网络超时(通过未连接到互联网)时,错误事件根本不会触发。我不知道我做错了什么。非常感谢帮助。
Here's the code:
这是代码:
$(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);
}
});
});
I'd like to add that this question was asked when jQuery was at version 1.4.2
我想补充一点,这个问题是在 jQuery 1.4.2 版本时提出的
采纳答案by Husky
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:
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!');
});
The timeout seems to do the trick and call the error handler, when there is no successful request after 10 seconds.
当 10 秒后没有成功请求时,超时似乎可以解决问题并调用错误处理程序。
I did a little blogposton this subject as well.
我也写了一篇关于这个主题的小博文。
回答by Jose Basilio
This is a known limitation with the native jsonp implementation in jQuery. The text below is from IBM DeveloperWorks
这是 jQuery 中原生 jsonp 实现的一个已知限制。以下文字来自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.)
JSONP 是一种用于构建 mashup 的非常强大的技术,但不幸的是,它并不是所有跨域通信需求的灵丹妙药。在投入开发资源之前,必须认真考虑它的一些缺点。首先,对于 JSONP 调用没有错误处理。如果动态脚本插入有效,您将被调用;如果没有,则什么也不会发生。它只是默默地失败。例如,您无法从服务器捕获 404 错误。您也不能取消或重新启动请求。但是,您可以在等待合理的时间后超时。(未来的 jQuery 版本可能具有 JSONP 请求的中止功能。)
However there's a jsonp plug-in available on GoogleCodethat provides support for error handling. To get started, just make the following changes to your code.
但是,GoogleCode上有一个 jsonp 插件可以提供错误处理支持。首先,只需对您的代码进行以下更改。
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:
然后修改您的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);
}
});
});
回答by Rob De Almeida
A solution if you're stuck with jQuery 1.4:
如果您坚持使用 jQuery 1.4,则有一个解决方案:
var timeout = 10000;
var id = setTimeout( errorCallback, timeout );
$.ajax({
dataType: 'jsonp',
success: function() {
clearTimeout(id);
...
}
});
回答by Marc
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.
这可能是 jQuery 的“已知”限制;然而,它似乎没有很好的记录。我今天花了大约 4 个小时试图了解为什么我的超时不起作用。
I switched to jquery.jsonpand it worked liked a charm. Thank you.
我切换到jquery.jsonp并且它的工作很吸引人。谢谢你。
回答by Peter Tate
Seems to be resolved as of jQuery 1.5. I've tried the code above and I get the callback.
似乎从 jQuery 1.5 开始解决。我试过上面的代码,我得到了回调。
I say "seems to be" because the documentation of the error callback for jQuery.ajax()still has the following note:
我说“似乎是”是因为jQuery.ajax()的错误回调文档仍然有以下注释:
Note: This handler is not called for cross-domain script and JSONP requests.
注意:跨域脚本和 JSONP 请求不会调用此处理程序。
回答by OiDatsMyLeg
The jquery-jsonp jQuery plugin mentioned in Jose Basilio'sanswercan now be found on GitHub.
Jose Basilio 的回答中提到的 jquery-jsonp jQuery 插件现在可以在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"
}
});
ImportantInclude 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).
重要在调用 $.jsonp() 中包含 callbackParameter 否则我发现回调函数永远不会被注入到服务调用的查询字符串中(当前版本为 jquery-jsonp 2.4.0)。
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".
我知道这个问题很老,但是使用 JSONP 处理错误的问题仍然没有“解决”。希望此更新能帮助其他人,因为此问题在 Google 中排名第一的“jquery jsonp 错误处理”。
回答by Hadrien Milano
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 :
监听脚本的 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;
}
What do you think of this solution ? Is it likely to cause compatibility issues ?
你觉得这个解决方案怎么样?是否有可能导致兼容性问题?