Как проверить, что заголовок запроса jQuery.ajax () имеет статус «304 Не изменен»? - PullRequest
46 голосов
/ 03 марта 2011

Как проверить, если jQuery.ajax () Заголовок запроса Статус «304 Не изменен»?

jqXHR.status обычно возвращает 200, даже если запрашиваемый заголовок равен «304 Not Modified».

ifModified:true не очень помогает , потому что нарушает запрос данных XHR.

Ответы [ 5 ]

64 голосов
/ 19 сентября 2012

Без обработки заголовков кэша вручную это невозможно.Обычно 304 ответа не предоставляются через XHR API :

Для 304 неизмененных ответов, которые являются результатом условного запроса, сгенерированного пользовательским агентом пользовательского агентадолжен действовать так, как если бы сервер дал ответ 200 OK с соответствующим содержимым .

jQuery обычно не знает, что было 304 ответа, потому что браузер говорит вежливую ложь JavaScript о том, чтона самом деле происходит по сети.

Но есть и хорошие новости (вроде): вы можете заставить Ajax выдать ответ 304, но только вручную установив кеш HTTPзаголовки If-Modified-Since или If-None-Match в запросе:

Пользовательский агент должен разрешить setRequestHeader() отменять автоматическую проверку кэша путем установки заголовков запроса (например, If-None-Match, * 1024).*), в этом случае необходимо передать 304 Неизмененные ответы.

Таким образом, вы можете использовать такой код:

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 нет информации о кеше для отправки (т. Е. Мы возвращаемся к случаю «первой выборки»).Нет никаких причин, по которым jQuery не может сохранить информацию в кэше, но в настоящее время это не так.

Суть здесь в том, чточто вы можете использовать заголовки кэша для получения ответа JavaScript 304, но вы не можете получить доступ к ETag или дате последнего изменения браузера для определенного ресурса.Таким образом, сам браузер может знать информацию о кешировании ресурса, а ваш код JavaScript - нет.В этом случае браузер будет использовать свои заголовки кэша, чтобы потенциально получить реальный ответ 304, но перенаправить ответ 200 на ваш код JavaScript, потому что JavaScript не отправлял никакой информации кэша.

Невозможно привести запросы JavaScript 304 в соответствие с фактическими ответами сети 304, поскольку информация о кеше, известная вашему браузеру, и информация о кеше, известная вашему коду JavaScript, могут отличаться непредсказуемым образом.Однако правильное получение 304 запросов в большинстве случаев достаточно для большинства практических нужд разработки.

Пример

Вот краткий пример сервера, написанный на Node.js (но он должен быть достаточно простым, чтобыпорт на другие языки):

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's 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); }

Этот скрипт будетвсегда видеть ответ 200, даже если браузер предоставляет заголовок запроса If-Modified-Since и получает 304 (который будет выполняться при всех запросах после первого, после того как браузер увидит заголовок ответа Last-Modifed сервера).

В отличие от этого сценарий будет всегда см. Ответ 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); }

Сценарий предоставляет собственный заголовок запроса If-Modified-Since (через два дня после даты последнего изменения сервера));он не полагается на то, что браузер предоставляет для If-Modified-Since, и поэтому ему разрешено (в соответствии со спецификацией XHR) видеть ответы 304.

Наконец, этот скрипт всегда будет видеть 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); }

Это связано с тем, что сценарий использует If-Modified-Since, предшествующий дате последнего изменения сервера, поэтому сервер всегда отправляет 200.Сервер не отправит 304, поскольку предполагает, что у клиента нет кэшированной копии самой последней версии (т. Е. Клиент объявляет, что он видел изменения с 12 февраля, но 13 февраля произошли изменения, которыеклиент, видимо, не видел).

0 голосов
/ 09 сентября 2014

Также заголовки будут кэшироваться, если ответ приходит из кэша.Я принял это как шанс.Мой сервер отправляет уникальный заголовок md5.Это не имеет такого же эффекта, как? Query = time ().Теперь на стороне JS проверьте последний заголовок md5 с текущим.Если вы получаете тот же заголовок MD5, что и раньше, ответ приходит из кеша.Я забыл все о JQuery, но увидел, что можно устанавливать и читать заголовки.

<?php
$oldMD5=filter_input(INPUT_SERVER,'HTTP_CONTENT_MD5',int);
if(!empty($oldMD5)){
  header('Content-MD5: '.(1+(int)$oldMD5));
}
--------------------------------------------------------------
<script>
var oldMD5=0;
//your Ajax implementation 
Ajax.setRequestHeader('Content-MD5',''+oldMD5);
var newMD5=parseInt(Ajax.getResponseHeader('Content-MD5'),10);
if(newMD5 && oldMD5<newMD5,10){
  oldMD5=newMD5;
  //not cached
}else{
  //cached
}

Это немного злоупотребление, потому что md5 должен быть хэшем для проверки того, что 'декодированные данные - это те же данные, которыебыли изначально отправлены ».

0 голосов
/ 20 сентября 2012

У меня есть вид реализации в https://github.com/laukstein/ajax-seo/blob/cbed03222d89f6f7e75dc49ce8882c30201bbb86/index.php#L266-274

var cache;

$.ajax({
    ...
    beforeSend: function() {
        cache = setTimeout(function() {
            console.log('The content not cached jet.');
        }, 300);
    },
    success: function(data) {
        if (cache) {
            clearTimeout(cache);
        }
    }
});
0 голосов
/ 23 марта 2012

откройте инспектор браузеров, и он покажет вам информацию о запросе ajax, включая статус.

для chrome, щелкните правой кнопкой мыши и выберите элемент inspect, затем перейдите на вкладку Сеть.

для firefox, просто используйте firebug и выполните те же шаги.

0 голосов
/ 03 марта 2011

Может попробовать это?

$.ajax({
    url: 'your-url',
    dataType: 'script',
    complete: function(xhr) { 
        if (xhr.status == 304) return;
        // or better: if (xhr.status != 200) return;
        // your code goes here
    }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...