如何使Microsoft XmlHttpRequest荣誉缓存控制指令

时间:2011-03-08 16:42:57

标签: xmlhttprequest msxml cache-control

我正在使用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显示文件实际上是从我的缓存中提供的:

enter image description here

所以我想指示XmlHttpRequest用户代理,任何超过0秒的缓存内容都太旧了。执行此操作的standards way是添加请求标头:

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 - Hypertext Transfer Protocol, Part 14: Header Field Definitions

  

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

     

最大年龄
  表示客户端是   愿意接受年龄的回应   不大于指定的时间   很快。除非最大化   指令也包括在内,客户端   不愿意接受陈旧   响应。

这正是我想要的。

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通用标头字段   用于指定指令   必须遵守所有缓存   请求/响应中的机制   链即可。指令指定行为   旨在防止缓存   不利地干扰了请求   或回应。这些指令   通常会覆盖默认缓存   算法。缓存指令是   单向的,存在的   请求中的指令不会   意味着同样的指令是   在答复中给出。

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。微软的XmlHttpRequest似乎并不尊重这一要求。

10 个答案:

答案 0 :(得分:16)

不幸的是,XMLHttpRequest对象是以这种方式设计的,因为它基于WinInet。此外,不建议从服务器端使用。您应该使用ServerXMLHttpRequest,它具有相同的功能,但取决于WinHTTP。有关详细信息,请参阅FAQServerXMLHttp文档中的说明指出:

  

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();

答案 1 :(得分:5)

我发现使用If-None-Match标头时,指定的值与上一个请求的ETag不匹配。

例如:

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

这可能会或可能不会要求回复包含ETag。 (我只在每个响应中使用包含ETag值的服务进行了尝试。)

答案 2 :(得分:1)

您是否可以在URI的末尾添加一个伪造参数,该参数随每个请求而变化?

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

答案 3 :(得分: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);

答案 4 :(得分:1)

我在标准Windows客户端的快速而肮脏的解决方法是 - 互联网选项
- 总则
- 浏览历史记录设置
- 检查存储页面的较新版本:
发痒"(x)每次访问网页时都会出现#34;
现在我的 Msxml2.XMLHTTP.x.0 对象不再使用缓存......

答案 5 :(得分:1)

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

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

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

我正在撰写HTML&适用于Windows 8的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.

来自What is Cache-Control: private?http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

所以,基本上,这永远不会创建一个缓存条目,因此不会添加我们知道多余的缓存条目,就像使用“缓存 - 缓存”一样。随机数参数。

答案 6 :(得分:0)

这个标题是针对服务器的,并且由于浏览器没有事件做任何请求,它是无用的。

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

http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?"+Math.random(), False, "", "");

答案 7 :(得分:0)

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

http://youlink?mysession=random_number

WOJTEK

答案 8 :(得分:0)

  

这样做的缺点是你用多份副本来充斥缓存   相同的内容。它可能是一个关于bug的http代理的黑客 - 但是a   真正的解决方案是使用缓存机制,而不是反对   他们。 -

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

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

答案 9 :(得分:0)

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

Header Pragma:no-cache

我希望通过IE头痛来拯救其他人。

BTW这是StackOverflow线程很好地阐明了Pragma和Cache-control之间的区别: Difference between Pragma and Cache-control headers?