34

我正在使用 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 部分:标头字段定义

其他指令允许用户代理修改基本过期机制。这些指令可以在请求中指定:

max-age
表示客户端愿意接受年龄不大于指定时间(以秒为单位)的响应。除非 maxstale 指令也包括在内,否则客户端不愿意接受过时的响应。

这正是我想要的。

Cache-Control: max-age=0正是我想要的,还是 MSXML 的XmlHttpRequest对象有问题?

更新一

这是 MSXML XmlHttpRequestCOM 对象:

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

更新二

max-age指令由客户端添加,以使所有缓存都遵守。来自 RFC:

Cache-Control 通用标头字段用于指定 请求/响应链上的所有缓存机制必须遵守的指令。这些指令指定旨在防止缓存对请求或响应产生不利影响的行为。这些指令通常会覆盖默认缓存算法。缓存指令是单向的,因为在请求中存在指令并不意味着要在响应中给出相同的指令。

Max-age 不适用于服务器;对服务器来说毫无意义。它适用于用户和服务器之间的所有缓存系统。

更新三

来自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 似乎没有满足这一要求。

4

10 回答 10

25

不幸的是,该XMLHttpRequest对象是这样设计的,因为它基于 WinInet。此外,不建议从服务器端使用。您应该使用ServerXMLHttpRequest,它具有相同的功能,但取决于WinHTTP。有关更多信息,请参阅常见问题解答。文档中的描述ServerXMLHttp指出:

HTTP 客户端堆栈提供更长的正常运行时间。新的 HTTP 子集中不包括对服务器应用程序不重要的 WinInet 功能,例如 URL 缓存、代理服务器的自动发现、HTTP/1.1 分块、脱机支持以及对 Gopher 和 FTP 协议的支持。

这意味着,而不是使用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();
于 2011-03-22T04:49:47.513 回答
8

我发现使用标头,指定一个与最后一个请求If-None-Match不匹配的值会起作用。ETag

例如:

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

这可能需要也可能不需要响应包含ETag. ETag(我只尝试了一个在每个响应中都包含一个值的服务。)

于 2012-01-06T15:25:21.127 回答
1

您能否在 URI 的末尾附加一个随每个请求更改的虚假参数?

http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?requestID=42", False, "", "");
于 2011-03-08T16:43:54.093 回答
1

我将其用于保持活动状态,并且效果很好。
诀窍是使用标头“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);
于 2011-11-07T16:00:40.910 回答
1

我在标准 Windows 客户端上的快速而肮脏的解决方法是
- Internet 选项
- 常规
-浏览历史记录设置
- 检查存储页面的较新版本:
痒痒“(x)每次我访问网页”
现在我的Msxml2.XMLHTTP.x.0对象不再使用缓存...

于 2014-05-07T16:08:19.743 回答
0

此标头用于服务器,并且由于浏览器不执行任何请求,因此无用。

一个简单的技巧是像这样加载页面:

http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?"+Math.random(), False, "", "");
于 2011-03-08T16:46:01.307 回答
0

对于旧的 msxml 库,我使用随机生成的 uri 地址值,例如:

http://youlink?mysession=random_number

wojtek

于 2011-09-19T15:34:57.863 回答
0

不利的一面是,您会用相同内容的多个副本淹没缓存。这可能是对有缺陷的 http 代理的破解——但真正的解决方案是使用缓存机制,而不是反对它们。——</p>

我同意这并不理想,也不是真正的解决方案,但 Mozilla 实际上建议将此作为一种解决方法,所以我认为它一定不会太糟糕 - https://developer.mozilla.org/en-US/docs/DOM /XMLHttpRequest/Using_XMLHttpRequest

此外,我正在努力解决这个问题。我不得不依靠我的用户来清除他们的浏览器(他们一直忘记这样做)。所以这对我来说是天赐之物!

于 2013-03-11T01:44:17.827 回答
0

尝试发送'cache-control: private'作为标头。这对我有用:

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

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

我正在为 Windows 8 编写一个 HTML 和 Javascript 应用程序,其中 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.

什么是缓存控制:私有?http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

因此,基本上,这将永远不会创建缓存条目,因此不会添加我们知道是多余的缓存条目,就像'cache-buster'随机数参数一样。

于 2014-06-16T11:52:46.240 回答
0

这让我发疯了。这个 SO 线程最接近提供答案。不幸的是,在测试期间,它们都没有真正为我工作。我发现测试正常工作的唯一解决方案是设置:

标头编译指示:无缓存

我希望它能拯救其他人的 IE 头痛。

顺便说一句,这是 StackOverflow 线程非常适合阐明 Pragma 和 Cache-control 之间的区别: Difference between Pragma and Cache-control headers?

于 2016-03-04T16:09:38.557 回答