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

я отправляю запрос, используя 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: Определения полей заголовка < / а>:

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

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

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

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

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

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

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

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

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

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

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

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

Из W3C XmlHttpRequest:

Если пользовательский агент реализует HTTP-кеш, он должен уважать Cache-Control заголовки запроса, установленные _ 15_ (например, 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, похоже, не выполняет это требование.


person Ian Boyd    schedule 08.03.2011    source источник


Ответы (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();
person Garett    schedule 22.03.2011
comment
Ты прав. Я только что проверил это, используя ServerXmlHttpRequest и WinHttpRequest. Эти двое вообще не кешируют. Хотя XmlHttpRequest выполняет кэширование, он не соответствует стандартам W3C в отношении запросов обхода этого кеша. +1 и принято. - person Ian Boyd; 12.04.2011
comment
Я пробовал использовать как WinHttp.WinHttpRequest.5.1, так и MSXML2.ServerXMLHTTP.6.0, но у меня это не сработало ... это может быть настройка сервера или что-то еще? - person thiagoleite; 01.12.2011
comment
@thiagoleite Что у вас не сработало? Какую ОС вы используете? Получили ли вы ошибку? - person Garett; 01.12.2011
comment
@Garret Это веб-ферма из 5 Windows Server 2008 64, IIS7. Я создал прокси в ASP Classic для использования RSS-канала, он просто делает запрос и анализирует xml. Я вообще не получаю ошибки, просто когда я делаю обновление в ленте, мой прокси не получает обновленную информацию. Я где-то читал, что ServerXmlHttpRequest имеет ошибку в отношении кеширования, но не могу вспомнить, где я ее читал. - person thiagoleite; 01.12.2011
comment
@thiagoleite Привет, это может потребовать нового вопроса, чтобы запросить дополнительную обратную связь. Это вполне может быть ошибкой, но я также хотел бы увидеть более подробную информацию, включая фрагменты кода, который вы используете. - person Garett; 14.12.2011

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

Eg:

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

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

person J. Mullaney    schedule 06.01.2012
comment
Прекрасно работает! - person Himanshu Patel; 26.04.2021

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

http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?requestID=42", False, "", "");
person blue t-shirt    schedule 08.03.2011
comment
Проблема в том, что он не обходит кеш, а просто отправляет отдельный запрос; заполняя мой кеш тысячами копий одного и того же ресурса. Я хотел бы знать, как соблюдать правила кеширования. - person Ian Boyd; 08.03.2011

Я использую это для сеанса проверки активности, и он отлично работает.
Уловка состоит в том, чтобы использовать заголовок «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);
person tranzitwww    schedule 07.11.2011
comment
If-Modified-Since противоположное тому, что я хочу. Добавление If-Modified-Since позволяет серверу возвращать 304 Not Modified. я хочу обойти кеш - не работать с ним - person Ian Boyd; 07.11.2011

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

person anonymous    schedule 07.05.2014

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

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

http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?"+Math.random(), False, "", "");
person jujule    schedule 08.03.2011
comment
Проблема в том, что он не обходит кеш, а просто отправляет отдельный запрос; заполняя мой кеш тысячами копий одного и того же ресурса. Я хотел бы знать, как соблюдать правила кеширования. - person Ian Boyd; 08.03.2011
comment
сервер отправляет только заголовок etag в ответе, поэтому кеш чисто на стороне клиента? вы можете заставить IE не кэшировать в опциях- ›параметры Интернета-› временные файлы- ›всегда проверять новый файл - person jujule; 09.03.2011
comment
Это не из-за того, что это собственное приложение, использующее XmlHttpRequest. - person Ian Boyd; 17.03.2011
comment
IMHO родные xmlhttpapps используют настройки кеша IE. поскольку они используют прокси IE - person jujule; 17.03.2011
comment
Я не могу изменить политику кеширования на каждой машине, на которой работает мое приложение (это просто не очень хорошая программа). Кроме того, W3C требует, чтобы если я указывал заголовок Cache-Control в моем запросе, реализация XmlHttpRequest должна его учитывать. - person Ian Boyd; 12.04.2011

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

http://youlink?mysession=random_number

Wojtek

person wojtek    schedule 19.09.2011
comment
Обратной стороной этого является то, что вы заполняете кеш несколькими копиями одного и того же контента. Это может быть хитрость вокруг глючных http-агентов, но реальное решение - работать с механизмами кэширования, а не против них. - person Ian Boyd; 19.09.2011

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

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

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

person Sue Smiles    schedule 11.03.2013

Попробуйте отправить '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. Для меня все вышесказанное отлично работает.

Я не был знаком с заголовком, поэтому немного покопался в cache-control: private ...

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: private? и http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

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

person Matt    schedule 16.06.2014

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

Заголовок Pragma: без кеширования

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

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

person MarkCheshire    schedule 04.03.2016