jQuery ajax (jsonp) игнорирует тайм-аут и не генерирует событие ошибки
-
05-07-2019 - |
Вопрос
Чтобы добавить базовую обработку ошибок, я хотел переписать фрагмент кода, который использовал $.getJSON 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.
Решение
В 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 секунд нет успешного запроса.
Я сделал небольшой блог-пост а> и на эту тему.
Другие советы
Это известное ограничение нативной реализации jsonp в jQuery. Ниже приведен текст из IBM DeveloperWorks
JSONP - очень мощная техника для создание коллажей, но, к сожалению, это не панацея от всех ваших междоменная связь Это имеет некоторые недостатки, которые должны быть приняты в серьезном рассмотрении, прежде чем выделение ресурсов для развития. В первую очередь ошибки нет обработка вызовов 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);
}
});
});
Решение, если вы застряли с 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. Я попробовал приведенный выше код и получил обратный вызов.
Я говорю "кажется" потому что документация об обратном вызове ошибки для jQuery.ajax () по-прежнему содержит следующее примечание: р>
Примечание. Этот обработчик не вызывается для междоменных сценариев и запросов JSONP.
Плагин 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"
}
});
Важный Включите callbackParameter в вызов $.jsonp(), иначе я обнаружил, что функция обратного вызова никогда не вводится в строку запроса вызова службы (по состоянию на версию 2.4.0 jquery-jsonp).
Я знаю, что этот вопрос старый, но проблема обработки ошибок с использованием JSONP до сих пор не «решена».Надеюсь, это обновление поможет другим, поскольку этот вопрос занимает первое место в Google по «обработке ошибок jquery jsonp».
Как насчет прослушивания события onerror сценария? У меня была эта проблема, и я решил ее, исправив метод jquery, в котором был создан тег script. Вот интересный фрагмент кода:
// 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;
}
Что вы думаете об этом решении? Это может вызвать проблемы совместимости?