Ответ 1
Без обработки заголовков кеша вручную это невозможно. Обычно 304 ответа не доступны через XHR API:
Для 304 Не измененных ответов, которые являются результатом условного запроса сгенерированного пользователем агента , пользовательский агент должен действовать так, как если бы сервер дал ответ 200 OK с соответствующим контентом.
jQuery обычно не знает, что был ответ 304, потому что браузер сообщает вежливой лжи JavaScript о том, что на самом деле происходит по сети.
Но есть хорошие новости (вид): вы можете получить Ajax для получения ответа 304, но только вручную настроив заголовки кэша HTTP If-Modified-Since
или If-None-Match
в запросе:
Пользовательский агент должен разрешить
setRequestHeader()
переопределять автоматическую проверку кеша, задавая заголовки запросов (например,If-None-Match
,If-Modified-Since
), и в этом случае должны быть переданы ответы 304 Not Modified.
Итак, вы можете использовать код, например:
var xhr = new XMLHttpRequest();
xhr.open("GET", "foo.html");
xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT");
xhr.send();
Одна из основных трудностей заключается в том, как вы знаете, какую дату последнего изменения или ETag отправить? В браузере есть информация о кеше, которую он использует для отправки запросов, но он не будет передавать эту информацию с помощью JavaScript. К счастью, jQuery отслеживает заголовки Last-Modified
и ETag
из ответов Ajax, поэтому вы можете использовать ifModified:true
, чтобы jQuery установил эти значения заголовка при следующем отправке запроса для этого ресурса.
Две вещи, чтобы отметить об этом:
-
304 ответа не содержат данных. Это по дизайну. Предполагается, что если вы решили использовать кеширование, вы должны иметь копию данных, уже находящихся в вашем кеше! Если получение данных с сервера не является проблемой (т.е. Потому что у вас еще нет данных), почему вы используете кеширование? Кэширование должно использоваться, когда у вас есть старые данные под рукой и нужны только новые данные; таким образом, получение данных с 304 не должно быть проблемой.
-
jQuery должен иметь дату последнего изменения или ETag (использовать с
If-None-Match
), сохраненную из предыдущего запроса. Процесс выполняется следующим образом:-
Первый выбор: jQuery не имеет информации о кеше, поэтому он не отправляет
If-Modified-Since
илиIf-None-Match
. Когда ответ вернется, сервер может объявить данные с последним изменением или ETag, которые хранятся в jQuery для дальнейшего использования. -
Последующие выборки: jQuery имеет информацию о кеше из последней выборки и пересылает эти данные на сервер. Если ресурс не изменился, запрос Ajax получает ответ 304. Если ресурс изменился, запрос Ajax получает ответ 200, а также новую информацию о кеше для jQuery, которая будет использоваться для следующей выборки.
-
jQuery не сохраняет информацию кэша (например, в файлах cookie) между перезагрузкой страницы. Поэтому первая выборка ресурса после перезагрузки страницы никогда не будет 304, потому что jQuery не имеет информации о кеше для отправки (т.е. Мы reset обратно в случай "первой выборки" ). Нет никакой причины, по которой jQuery не может сохранять информацию о кеше, но в настоящее время это не так.
-
В итоге вы можете использовать заголовки кеша, чтобы получить ответ JavaScript 304, но вы не можете получить доступ к собственному ETag браузера или дате последнего изменения для определенного ресурса. Таким образом, сам браузер может знать кеширование информации о ресурсе, но ваш код JavaScript этого не делает. В этом случае браузер будет использовать свои заголовки кеша, чтобы получить реальный ответ 304, но перенаправить ответ 200 на ваш код JavaScript, поскольку JavaScript не отправил информацию о кеше.
Невозможно, чтобы JavaScript 304-запросы полностью совпадали с фактическими ответами сети 304, поскольку информация о кеше, известная вашему браузеру, и информация о кеше, известная вашим кодом JavaScript, могут отличаться непредсказуемыми способами. Однако получение 304 запросов в большинстве случаев является достаточным для большинства практических потребностей в разработке.
Пример
Вот пример сервера, написанный в Node.js(но он должен быть достаточно простым для переноса на другие langauges):
require("http").createServer(function (req, res) {
console.log(req.headers["if-modified-since"]);
// always send Last-Modifed header
var lastModDate = "Fri, 13 Feb 2013 13:43:19 GMT";
res.setHeader("Last-Modified", lastModDate);
// if the request has a If-Modified-Since header,
// and it newer than the last modification,
// then send a 304 response; otherwise send 200
if(req.headers["if-modified-since"] &&
Date.parse(lastModDate) <= Date.parse(req.headers["if-modified-since"])) {
console.log("304 -- browser has it cached");
res.writeHead(304, {'Content-Type': 'text/plain'});
res.end();
} else {
console.log("200 -- browser needs it fresh");
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('some content');
}
}).listen(8080);
При запуске этого сервера вы можете загрузить страницу в своем браузере и выполнить два разных теста в консоли браузера:
var xhr = new XMLHttpRequest();
xhr.open("GET", "/");
xhr.send();
xhr.onload = function() { console.log(xhr.status); }
Этот script всегда будет видеть ответ 200
, даже если браузер поставляет заголовок запроса If-Modified-Since
и получает 304
(который будет иметь все запросы после первого, после того, как браузер увидит сервер Last-Modifed
заголовок ответа).
В отличие от этого script всегда будет отображаться ответ 304:
var xhr = new XMLHttpRequest();
xhr.open("GET", "/");
xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT");
xhr.send();
xhr.onload = function() { console.log(xhr.status); }
script предоставляет свой собственный заголовок запроса If-Modified-Since
(через два дня после последней версии сервера); он не полагается на то, что браузер предоставляет для If-Modified-Since
, и поэтому разрешено (по спецификации XHR) видеть 304 ответа.
Наконец, этот script всегда будет видеть 200
:
var xhr = new XMLHttpRequest();
xhr.open("GET", "/");
xhr.setRequestHeader("If-Modified-Since", "Fri, 12 Feb 2013 13:43:19 GMT");
xhr.send();
xhr.onload = function() { console.log(xhr.status); }
Это связано с тем, что script использует If-Modified-Since
, который предшествует дате последнего изменения сервера, поэтому сервер всегда отправляет 200
. Сервер не отправит 304
, поскольку предполагает, что у клиента нет кэшированной копии самой последней версии (т.е. Клиент объявляет, что он видел изменения с 12 февраля, но 13 февраля было внесено изменение, клиент, видимо, не видел).