В последние пару дней мне было очень весело отлаживать проблемы наших JavaScript SPAs на oldIE (слава Богу, мы получили лицензии Browserstack). В любом случае, я столкнулся с довольно интересным поведением IE при вызовах jQuery Ajax и кэшированных ответах.
«HTTP / 1.1 304 не изменен»: ни за что! Ты меня не поймаешь
Чтобы этот эксперимент работал, убедитесь, что ваш кеш браузера активен.
Перенесите следующий ajax-запрос в статический файл JSON
$.ajax({
url: '/data.json',
type: 'GET',
dataType: 'JSON',
success: function(data, textStatus, jqXHR){
console.log('Data received: ' + data);
}
});
Первый запрос, вероятно, возвращается через некоторое Http/1.1 200 OKвремя, а любой последующий (если на сервере активировано кэширование) возвращается с Http/1.1 304 Not Modified. Вы хорошо видите это на панели Chrome Network
Теперь предположим, что вы хотите выполнить какую-то операцию только Http/1.1 200над 304запросами, а не над ними . Достаточно просто, правда? Вы просто сверяете с jqXHR.statusобъектом:
...
success: function(data, textStatus, jqXHR){
if(jqXHR.status === 200){
console.log('Got a good request');
}
}
Интересно, что для вышеупомянутого запроса я бы получил
Got a good request Got a good request Got a good request
… Напечатано на моей консоли и, действительно, при проверке по запросу jqXHR jqXHR.statusвозвращается как 200для, Http/1.1 200так и для Http/1.1 304. Почему это?? Это дизайн объекта XMLHttpRequest .
Для 304 неизмененных ответов, которые являются результатом условного запроса, сгенерированного пользовательским агентом, пользовательский агент должен действовать так, как если бы сервер дал ответ 200 OK с соответствующим содержимым. […] W3c.org [RFC2616]
Подожди .. есть способ!
На самом деле есть способ также получить 304коды состояния в вашем обратном вызове jQuery ajax. Очередной раз:
… Пользовательский агент должен разрешить setRequestHeader () переопределять автоматическую проверку кэша, устанавливая заголовки запроса (например, If-None-Match, If-Modified-Since), в этом случае должны передаваться ответы 304 Not Modified. w3c.org [RFC2616]
Но обратите внимание, у вас нет доступа к информации браузера If-Modified-Sinceили E-Tag. Однако jQuery отслеживает это и позволяет использовать ifModifiedфлаг для параметров ajax:
$.ajax({
url: '/data.json',
type: 'GET',
dataType: 'JSON',
ifModified:true,
success: function(data, textStatus, jqXHR){
if(jqXHR.status === 200){
console.log('Got a good request');
} else {
console.log('Hey, a 304 request');
}
console.log('Data: ' + data);
}
});
Выполняя это сейчас снова, где первый запрос возвращает 200, а последующие 300 статус ответа дает мне следующее в журнале:
Got a good request Data: <snip>JSON string</snip> Hey, a 304 request Data: undefined Hey, a 304 request Data: undefined
Черт возьми ?? Да, опять это по замыслу:
[…] В этом случае 304 Неизмененные ответы должны быть пропущены через […]
… и действительно, 304ответ не несет никаких данных.
Хорошо, но почему это должно быть проблемой?
Обычно это не так, просто не ставьте ifModifiedфлаг, и вы в порядке. Однако в моем конкретном сценарии мне пришлось анализировать изменения в определенном заголовке ответа, поэтому я использовал такую ajaxComplete(..)функцию, как
var currentHeaderVal = undefined;
$(document).ajaxComplete(function(e, xhr, settings){
var newHeaderVal = xhr.getResponseHeader('MY-HEADER');
if(currentHeaderVal !== newHeaderVal){
//do something fancy
}
});
На стороне сервера какой-то механизм ввел MY-HEADERзначение. Идея проста, и она также работает (на Chrome, Firefox и любом другом достойном браузере), но, к удивлению, на IE это не так. При использовании xhr.getResponseHeader('MY-HEADER')IE возвращает заголовки из ранее кэшированного запроса, которые, очевидно, уже не обязательно действительны.
Таким образом, идея состояла в том, чтобы проверить xhr.status, чтобы просто прочитать заголовки из 200запросов типа, как
var newHeaderVal = xhr.getResponseHeader('MY-HEADER');
if(xhr && xhr.status === 200){
if(currentHeaderVal !== newHeaderVal){
//do something fancy
}
}
… но, как мы теперь знаем, это не сработает.

