Как заставить Microsoft XmlHttpRequest соблюдать директиву контроля кэша

Я выдаю запрос, используя объект MSXML XmlHttpRequest:

IXMLHttpRequest http = new XmlHttpRequest();
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.send();

И send успешно, и я получаю свои данные XML.

Кроме этого XmlHttpRequest на самом деле не попал в сеть (я вижу, что не было фактического http запроса). И Process Monitor показывает, что файл фактически обслуживается из моего кэша:

Поэтому я хочу поручить XmlHttpRequest Пользовательский агент, что любой кэшированный контент старше 0 секунд слишком стар. Стандартный способ сделать это - добавить заголовок запроса:

Cache-Control: max-age=0

отправить запрос:

http = new XmlHttpRequest();
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "max-age=0");
http.send();

И send успешно, и я получаю свои данные XML.

Кроме этого XmlHttpRequest на самом деле не попал в сеть (я вижу, что не было фактического http запроса). И Process Monitor показывает, что файл фактически обслуживается из моего кэша.

Так что не так? Является max-age не делать то, что я думаю, что делает?

Из RFC 2616 - Протокол передачи гипертекста, часть 14: Определения полей заголовка:

Другие директивы позволяют агенту пользователя изменять базовый механизм истечения срока действия. Эти директивы МОГУТ быть указаны по запросу:

максимальный возраст
Указывает, что клиент готов принять ответ, возраст которого не превышает указанное время в секундах. Если не включена максимальная директива, клиент не желает принимать устаревший ответ.

Что именно то, что я хочу.

Является Cache-Control: max-age=0 не совсем то, что я хочу, или MSXML XmlHttpRequest объект глючит?

Обновите Один

Это MSXML XmlHttpRequest COM-объект:

  • CLSID: {88d96a0a-f192-11d4-a65f-0040963251e5}
  • ProgID: Msxml2.XMLHTTP.6.0

Обновление Два

max-age Директива добавлена ​​клиентом для всех кешей. Из RFC:

Поле общего заголовка Cache-Control используется для указания директив, которым ДОЛЖНЫ подчиняться все механизмы кэширования в цепочке запросов / ответов. Директивы определяют поведение, предназначенное для предотвращения неблагоприятного вмешательства кэшей в запрос или ответ. Эти директивы обычно переопределяют алгоритмы кэширования по умолчанию. Директивы Cache являются однонаправленными в том смысле, что наличие директивы в запросе не означает, что в ответе должна быть указана та же директива.

Макс-возраст не для сервера; для сервера это не имеет смысла. Он предназначен для всех систем кеширования между пользователем и сервером.

Обновление три

Из W3C XmlHttpRequest:

Если пользовательский агент реализует HTTP-кэш, он должен соблюдать Cache-Control заголовки запроса, установленные setRequestHeader() (например, Cache-Control: no-cache обходит кеш). Не должен отправлять Cache-Control или же Pragma запрашивать заголовки автоматически, если конечный пользователь явно не запрашивает такое поведение (например, путем перезагрузки страницы).

Следуя их примеру, я попытался использовать no-cache директива:

http = new XmlHttpRequest();
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "no-cache");
http.send();

И XmlHttpRequest клиент по-прежнему полностью обслуживает запросы из кэша, не обращаясь к серверу вообще.

W3C говорит, что если есть кеш, он должен соблюдать Cache-Control если это установлено через setRequestHeader, Microsoft XmlHttpRequest, похоже, не выполняет это требование.

10 ответов

Решение

К сожалению XMLHttpRequest Объект был разработан таким образом, потому что он основан на WinInet. Кроме того, не рекомендуется использовать со стороны сервера. Вы должны использовать ServerXMLHttpRequest, который имеет такую ​​же функциональность, но зависит от WinHTTP вместо. Смотрите FAQ для получения дополнительной информации. Описание от ServerXMLHttp документация гласит, что:

Стек HTTP-клиента обеспечивает более длительное время безотказной работы. Функции WinInet, которые не являются критичными для серверных приложений, такие как кэширование URL-адресов, автоматическое обнаружение прокси-серверов, разбиение на части HTTP/1.1, автономная поддержка и поддержка протоколов Gopher и FTP, не включены в новое подмножество HTTP.

Это означает, что вместо использования XmlHttpRequest:

IXMLHTTPRequest http = CreateComObject("Msxml2.XMLHTTP.6.0");     http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "max-age=0");
http.send();

Вы можете использовать ServerXmlHttpRequest:

IXMLHTTPRequest http = CreateComObject("Msxml2.ServerXMLHTTP");
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "max-age=0");
http.send();

или WinHttpRequest:

IWinHttpRequest http = CreateComObject("WinHttp.WinHttpRequest.5.1");
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "max-age=0");
http.send();

Я обнаружил, что с помощью If-None-Match заголовок, указывая значение, которое не соответствует ETag последний запрос будет работать.

Например:

req.open("GET", url, false);
req.setRequestHeader("If-None-Match", "\"doesnt-match-anything\"");
req.send();

Это может или не может требовать, чтобы ответы включали ETag, (Я пробовал только с сервисом, который включает в себя ETag значение в каждом ответе.)

Я использую это для поддержания активности, и это прекрасно работает.
Хитрость заключается в том, чтобы использовать заголовок "If-Modified-Since" с более новым значением, чем кэшированное браузером.

g_AjaxObj.onreadystatechange = function() { if(g_AjaxObj.readyState === 4) { AjaxOnComplete_("KeepAlive"); }};
g_AjaxObj.open('GET', URL, true);
g_AjaxObj.setRequestHeader("If-Modified-Since", new Date().toUTCString());
g_AjaxObj.send(null);

Попробуйте отправить 'cache-control: private' в качестве заголовка. Это сработало для меня:

var request = new XMLHttpRequest();
request.open("GET", 'http://myurl.com' , false); 

request.setRequestHeader("cache-control", "private");

Я пишу приложение HTML & Javascript для Windows 8, в котором игнорируются как no-cache, так и max-age. Для меня вышесказанное работает просто отлично.

Я не был знаком с заголовком, поэтому немного покопался в управлении кешем: приват...

Indicates that all or part of the response message is intended for a single user and MUST NOT be cached by a shared cache, such as a proxy server.

Из чего такое Cache-Control: приватный? и http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

Таким образом, в принципе, это никогда не создаст запись в кеше и, следовательно, не добавит записи в кеш, которые, как мы знаем, являются излишними, как в случае с параметром случайного числа "cache-buster".

Не могли бы вы добавить фиктивный параметр в конце вашего URI, который меняется с каждым запросом?

http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?requestID=42", False, "", "");

Мой быстрый и грязный обходной путь на стандартном клиенте Windows был
- Свойства обозревателя
- Генеральный
- Настройки просмотра истории
- Проверьте наличие новых версий сохраненных страниц:
щекотать "(х) Каждый раз, когда я посещаю веб-страницу"
Теперь мой объект Msxml2.XMLHTTP.x.0 больше не использует кэш...

Это сводило меня с ума. Эта тема была ближе всего к ответу. К сожалению, во время тестирования никто из них на самом деле не работал для меня. Единственное решение, которое я нашел, которое проверялось на корректную работу, это настройка:

Заголовок Pragma: без кеша

Я надеюсь, что это спасает других от головной боли IE.

Кстати, это поток Stackru - отличный способ пролить свет на разницу между Pragma и Cache-control: разница между Pragma и Cache-control заголовками?

Для старой библиотеки msxml я использую случайное сгенерированное значение для адреса uri, например:

HTTP: // youlink mysession = случайное_число

Войтек

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

Я согласен, что это не идеальное и не совсем решение, но Mozilla на самом деле рекомендует это в качестве обходного пути, поэтому я считаю, что это не должно быть слишком ужасно - https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest

Кроме того, я рвал на себе волосы, пытаясь решить эту проблему. Я должен был положиться на своих пользователей, чтобы очистить их браузер (что они постоянно забывают делать). Так что это находка для меня!

Этот заголовок предназначен для сервера, и, поскольку браузер не выполняет никаких действий, он бесполезен.

Простой трюк - загрузить страницу следующим образом:

http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?"+Math.random(), False, "", "");
Другие вопросы по тегам