JQuery AJAX запускает обратный вызов ошибки при выгрузке окна - как я могу отфильтровать выгрузку и только поймать реальные ошибки?
Если я перемещаюсь от страницы в середине запроса $.ajax(), он вызывает обратный вызов ошибки. Я тестировал в Safari и FF запросы GET и POST.
Одним из возможных решений было бы прервать все запросы AJAX на выгрузке страницы, но обработчик ошибок вызывается перед выгрузкой, поэтому это не представляется возможным.
Я хочу иметь возможность обрабатывать REAL-ошибки, такие как 500s изящно на стороне клиента, с вежливым предупреждением или модальным диалогом, но я не хочу, чтобы эта обработка вызывалась, когда пользователь переходит от страницы.
Как это сделать?
-
(Также странно: при переходе от страницы обработчик ошибок говорит, что параметр textStatus является "ошибкой", тот же, который он выбрасывает при получении запроса 500/bad.)
Ответы
Ответ 1
В обратном вызове ошибки или $. ajax у вас есть три входных аргумента:
function (XMLHttpRequest, textStatus, errorThrown) {
this; // options for this ajax request
}
Вы можете напрямую проверить xhr.status
, чтобы получить код ответа HTTP, например:
$.ajax({
url: "test.html",
cache: false,
success: function(html){
$("#results").append(html);
},
error: function (xhr, textStatus) {
if (xhr.status == 500) {
alert('Server error: '+ textStatus);
}
}
});
Edit:
Чтобы рассказать разницу между соединением, нарушенным браузером, и случаем, когда сервер выключен (комментарий jasonmerino):
При выгрузке xhr.readyState должно быть 0, где для нечувствительного сервер xhr.readyState должен быть 4.
Ответ 2
Это трудно справиться правильно во всех ситуациях. К сожалению, во многих популярных браузерах xhr.status
является тем же (0
), если вызов AJAX отменяется навигацией или сервером, который не работает/не отвечает. Так что этот метод редко работает.
Вот набор очень "практических" хаков, которые я накопил, которые работают достаточно хорошо в большинстве случаев, но все же не являются пуленепробиваемыми. Идея состоит в попытке поймать события навигации и установить флаг, который проверяется в обработчике ошибок AJAX. Вот так:
var global_is_navigating = false;
$(window).on('beforeunload',function() {
// Note: this event doesn't fire in mobile safari
global_is_navigating = true;
});
$("a").on('click',function() {
// Giant hack that can be helpful with mobile safari
if( $(this).attr('href') ) {
global_is_navigating = true;
}
});
$(document).ajaxError(function(evt, xhr, settings) {
// default AJAX error handler for page
if( global_is_navigating ) {
// AJAX call cancelled by navigation. Not a real error
return;
}
// process actual AJAX error here.
});
Ответ 3
(Я бы добавил это в качестве комментария к основному ответу, но еще не набрал достаточного количества баллов, чтобы сделать это!)
Я также вижу это в FF4 и Chrome (9.0.597.107). Возможно, в другом месте, но это достаточно плохо для меня, чтобы это исправить!
Одна из вещей, которые нечетны в этой ситуации, заключается в том, что возвращается XMLHttpRequest.status === 0
Это похоже на надежный способ обнаружения этой ситуации и в моем конкретном случае прервать обработку пользовательских ошибок, отображаемую пользователю:
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (XMLHttpRequest.status === 0) return;
// error handling here
}
Также стоит упомянуть, что в предположении, что может быть проблемой в JSON-анализе того, что браузер возвращает к вызову $.ajax(), я также попытался заменить собственный JSON.stringify на версию Douglas Crockford (https://github.com/douglascrockford/JSON-js), но это не имело значения.
Ответ 4
Обратный вызов ошибки должен получить ссылку на объект XHR, проверить код состояния, чтобы увидеть, является ли это ошибкой сервера или нет?
Ответ 5
Если вы используете функции jQuery, такие как $.get
, $.post
, $.ajax
..., то вы можете использовать параметр text_status
, чтобы проверить, какой тип сбоя:
request = $.get('test.html', function(data){
//whatever
}).fail(function(xhr, text_status, error_thrown) {
if(text_status!== 'abort'){
console.warn("Error!!");
}
});
Из jQuery docs:
jqXHR.fail(функция (jqXHR, textStatus, errorThrown) {}); Альтернативная конструкция опции обратного вызова ошибки, метод .fail() заменяет устаревший метод .error(). Обратитесь к разделу deferred.fail() для подробности реализации.