我试图帮助同事调试过去6个月来一直没有问题的问题。在最近部署ASP.NET MVC 2应用程序之后,强制用户打开或保存PDF文件的FileResult
响应在客户端计算机上存在的问题足够长,以便PDF阅读器打开它们。
早期版本的IE(特别是6)是受影响的唯一浏览器。 Firefox和Chrome以及较新版本的IE(> 8)都按预期运行。考虑到这一点,下一节将定义重新创建问题所需的操作。
href
属性的普通超链接)。在操作方法中,标头设置为指示浏览器如何缓存响应。他们是:
response.AddHeader("Cache-Control", "public, must-revalidate, post-check=0, pre-check=0");
response.AddHeader("Pragma", "no-cache");
response.AddHeader("Expires", "0");
对于那些不熟悉headers所做的事情的人:
一个。 缓存控制:公开
表示任何缓存都可以缓存响应,即使它通常是非缓存的,也可以只在非共享缓存中缓存。
湾缓存控制:必须重新验证
当缓存接收到的响应中存在must-revalidate指令时,该缓存必须在声明变为陈旧后才能使用该条目 后续请求,而不首先使用原始服务器重新验证它
℃。 缓存控制:预检(与IE5一起推出)
定义以秒为单位的间隔,在此之后必须检查实体的新鲜度。检查可能在用户显示资源后发生,但确保在下一次往返时缓存的副本将是最新的。
d。 缓存控制:后检查(随IE5一起推出)
定义以秒为单位的间隔,在此间隔之前,必须先检查实体的新鲜度,然后才能向用户显示资源。
即 Pragma:no-cache (以确保向后兼容HTTP / 1.0)
当请求消息中存在no-cache指令时,应用程序应该将请求转发给源服务器,即使它具有所请求内容的缓存副本
F。的到期
Expires entity-header字段给出了将响应视为过时的日期/时间。
我们从操作中返回文件
return File(file, "mime/type", fileName);
向用户显示“打开/保存”对话框
此处有六个其他应用程序使用相同的标题强制Excel,CSV,PDF,Word以及大量其他内容在用户处使用,而且从未出现过问题。
在返回FileResult
之前,在操作方法中设置响应标头。我已经让我的同事尝试创建一个继承自FileResult
的新类,而是覆盖ExecuteResult
方法,以便修改标题,然后改为base.ExecuteResult()
- 没有任何地位。
我有预感" Expires" " 0"的标题是罪魁祸首。根据{{3}},将其设置为" 0"暗示"已经过期。"我确实希望它过期,我只是不希望IE在文件系统中删除它之前,处理它的应用程序有机会打开它。
一如既往,谢谢!
在进一步测试(使用Fiddler检查标头)后,我们发现我们认为设置的响应头不是浏览器解释的响应头。由于我自己并不熟悉代码,因此我没有意识到一个潜在的问题:标题在操作方法之外被踩到了。
尽管如此,我还是要打开这个问题。仍然很突出的是:Expires
标题之间似乎存在一些差异,其值为0
与-1
。如果任何人可以通过设计声称存在差异,对于IE ,我仍然希望听到它。但是,对于解决方案,上述标头可以按预期工作,并且所有浏览器中的Expires
值都设置为-1
。
帖子this W3C article详细说明了借助于设置Expires = 0可以在所有浏览器中阻止缓存。我仍未在此0
vs {{1}上销售} argument ...
答案 0 :(得分:16)
我认为你应该使用
HttpContext.Current.Response.Cache.SetMaxAge (new TimeSpan (0));
或
HttpContext.Current.Response.Headers.Set ("Cache-Control", "private, max-age=0");
设置max-age=0
,这意味着不再需要缓存重新验证(请参阅here)。如果您在标题中另外设置了ETag
,并且数据中包含一些自定义哈希校验和,则上一个请求中的ETag将被发送到服务器。服务器能够返回数据,或者,如果数据与之前完全相同,则它可以返回空体和HttpStatusCode.NotModified
作为状态代码。如果Web浏览器将从本地浏览器缓存中获取数据。
我建议你使用Cache-Control: private
强制两个重要的事情:1)关闭缓存代理上的数据,这有时非常积极的缓存设置2)它将允许缓存数据,但不允许与其他用户共享缓存。它可以解决隐私问题,因为您返回给一个用户的数据可能不被其他用户读取。顺便说一句,代码HttpContext.Current.Response.Cache.SetMaxAge (new TimeSpan (0))
默认情况下在HTTP标头中设置Cache-Control: private, max-age=0
。如果您确实想使用Cache-Control: public
,可以使用SetCacheability (HttpCacheability.Public);
覆盖行为,或使用Headers.Set
代替Cache.SetMaxAge
。
如果您有兴趣研究更多HTTP协议的缓存选项,我建议您阅读caching tutorial。
更新:我决定写一些更多信息来清除我的位置。对应于来自维基百科的the information,即使像Mosaic 2.7,Netscape 2.0和Internet Explorer 3.0这样的旧网络浏览器也支持1996年3月,RFC 2068中描述的HTTP / 1.1预标准。所以我想(但不测试它)旧的Web浏览器支持max-age=0
HTTP标头。无论如何,Netscape 2.06和Internet Explorer 4.0最终支持HTTP 1.1。
所以你应该先问你:你使用哪种HTML标准?您是否仍然使用HTML 2.0而不是1997年1月发布的更晚HTML 3.2?我想您至少使用了1997年12月发布的HTML 4.0。因此,如果您至少在HTML 4.0中构建应用程序,您的站点可以面向支持HTTP 1.1的Web客户端,并忽略(不支持)Web客户端。不支持HTTP 1.1。
现在将其他“Cache-Control”标头称为“private,max-age = 0”。在我看来,包括标题是纯粹的偏执狂。由于我自己有一些缓存问题,我还尝试包含不同的其他标题,但后来仔细阅读了RFC2616的第14.9节后,我只使用了“Cache-Control:private,max-age = 0”。
唯一可以另外讨论的“Cache-Control”标题是我之前引用的14.9.4节中描述的“必须重新验证”。这是引用:
必须重新验证指令是支持可靠性所必需的 某些协议功能的操作。在所有情况下 HTTP / 1.1缓存必须遵守must-revalidate指令;特别是, 如果缓存由于任何原因无法到达原始服务器,它必须 生成504(网关超时)响应。
服务器应该只发送必须重新验证的指令 无法重新验证实体上的请求可能会导致 不正确的操作,例如无声无息的财务 交易。收件人不得采取任何自动操作 违反此指令,并且不得自动提供 如果重新验证失败,则实体的未经验证的副本。
虽然这是 不推荐,用户代理在严重连接下运行 约束可能违反此指令,但如果是,则必须明确 警告用户已提供未经验证的响应。该 必须在每个未经验证的访问上提供警告,并且应该 需要明确的用户确认。
有时如果我遇到Internet连接问题,我会看到带有“Gateway Timeout”消息的空白页面。它来自“必须重新验证”指令的使用。我认为“网关超时”消息并不能真正帮助用户。
所以,如果人们在打电话给他的老板时听到“忙碌”信号,他们更愿意开始自我毁灭程序,还应该在“Cache-Control”标题中使用“must-revalidate”指令。我推荐的其他人只使用“Cache-Control:private,max-age = 0”,仅此而已。
答案 1 :(得分:2)
我知道这已经很晚了,但是这个链接可能对每个对这个主题感兴趣的人都有很大的帮助:http://dotnet.dzone.com/articles/output-caching-aspnet-mvc
答案 2 :(得分:0)
对于IE,我记得必须设置Expires: -1
。 How to prevent caching in Internet Explorer似乎通过以下代码段确认了这一点。
<% Response.CacheControl = "no-cache" %>
<% Response.AddHeader "Pragma", "no-cache" %>
<% Response.Expires = -1 %>
回顾代码,这就是我发现的。另外,我依稀记得,如果设置Cache-Control: private
,则SSL可能无法正常运行。
Response.AddHeader("Cache-Control", "no-cache");
Response.AddHeader("Expires", "-1");
另外,So, You Don't Want To Cache, Huh?提及-1
,但使用Response.Cache
上的方法代替:
// Stop Caching in IE
Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
// Stop Caching in Firefox
Response.Cache.SetNoStore();
但是,ASP Page caching issue (IE8)表示此代码不起作用。