jQuery ajax(jsonp)忽略超时并且不会触发错误事件
为了添加一些基本的error handling,我想重写一段代码,使用jQuery的$ .getJSON从Flickr中提取一些照片。 这样做的原因是$ .getJSON不提供error handling或超时工作。
由于$ .getJSON仅仅是$ .ajax的一个包装,所以我决定重写这个东西,并且让人惊喜,它完美的工作。
现在乐趣开始了。 当我故意引起404(通过更改URL)或导致networking超时(通过不被连接到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时,这个问题被问到
jQuery 1.5和更高版本更好地支持使用JSONP请求进行error handling。 但是,您需要使用$.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秒后没有成功的请求时调用error handling程序。
我也在这个主题上做了一个小博客 。
这是jQuery中本地jsonp实现的一个已知限制。 以下文本来自IBM DeveloperWorks
JSONP是构build混搭的一个非常强大的技术,但是,不幸的是,它不能解决你所有的跨域通信需求。 在投入发展资源之前,必须认真考虑一些弊端。 首先,对于JSONP调用没有error handling。 如果dynamic脚本插入工作,你会被调用; 如果没有,没有任何反应。 它只是默默地失败。 例如,您无法从服务器捕获404错误。 您也不能取消或重新启动请求。 但是,您可以在等待一段合理的时间后超时。 (未来的jQuery版本可能会有JSONP请求的中止function。)
但是, GoogleCode上提供了一个jsonp插件,用于支持error handling。 要开始,只需对代码进行以下更改。
您可以下载它,或者只是添加脚本引用到插件。
<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); } }); });
一个解决scheme,如果你坚持使用jQuery 1.4:
var timeout = 10000; var id = setTimeout( errorCallback, timeout ); $.ajax({ dataType: 'jsonp', success: function() { clearTimeout(id); ... } });
这可能是jQuery的“已知”限制; 但是,它似乎没有很好的文件。 我今天花了大约4个小时,试图理解为什么我的超时不工作。
我切换到jquery.jsonp ,它的工作就像一个魅力。 谢谢。
似乎jQuery 1.5的解决。 我已经尝试了上面的代码,并得到callback。
我说“似乎是”,因为jQuery.ajax()的错误callback的文档仍然有以下说明:
注意:此处理程序不会被调用用于跨域脚本和JSONP请求。
在Jose Basilio的 答案中提到的jquery-jsonp jQuery插件现在可以在GitHub上find 。
不幸的是,这个文档有些简陋,所以我提供了一个简单的例子:
$.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" } });
重要在call中包含callbackParameter $ .jsonp()否则我发现callback函数永远不会被注入服务调用的查询string(当前版本为jquery-jsonp 2.4.0版本)。
我知道这个问题是旧的,但使用JSONP处理错误的问题仍然没有解决。 希望这个更新会帮助其他人,因为这个问题是谷歌“jQuery jsonperror handling”中排名最高的。
听剧本的恐怖事件怎么样? 我有这个问题,并通过修补脚本标记创buildjquery的方法来解决它。 这里有一些有趣的代码:
// 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; }
你对这个解决scheme有什么看法? 是否可能导致兼容性问题?