调查显示,并非所有浏览器都以统一的方式遵守HTTP缓存指令。出于安全考虑,大多数公司不希望应用中的某些页面被网页浏览器缓存,永远都不可以。这必须至少适用于以下浏览器:Internet Explorer 、Firefox 、Chrome等。
假如现在有一个需求:我们点击网页的注销按钮后,仍然可以点击后退按钮查看缓存的页面。那么该若何做到呢?
引言
要想理清这个需求,我们就得先认识一下与HTTP缓存控制相关的头部字段(以下适用于所有提到的客户端(和代理)):
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
简单解释一下上面字段:
Cache-Control: no-cache, no-store, must-revalidate
no-cache
:这个指令告诉浏览器或其他客户端每次请求资源时,都必须向服务器发送请求进行验证,即使缓存中存在该资源。no-store
:这是指令告诉所有缓存(包括浏览器缓存和代理服务器缓存)不得存储任何版本的响应。must-revalidate
:这个指令告诉缓存,在使用缓存的资源之前,必须先向原始服务器验证其有效性。即使缓存的资源没有过期,也必须进行验证。
Pragma: no-cache
no-cache
:这个字段是HTTP/1.0
版本中的指令,用于实现与HTTP/1.1
中的Cache-Control: no-cache
相似的行为。尽管HTTP/1.1版本已经广泛使用,但一些老旧或不规范的客户端可能仍然支持这个字段。因此,在某些情况下,为了确保兼容性,开发者可能会同时使用Pragma: no-cache
和Cache-Control: no-cache
。
Expires: 0
Expires
:这个头部字段提供了一个日期/时间,之后缓存的资源将被视为过期。设置为0意味着资源立即过期,因此不会被缓存。这个字段在HTTP/1.0和HTTP/1.1中都有定义,但在HTTP/1.1中,它的优先级低于Cache-Control
。
如果你不关心IE6及其在使用HTTPS服务页面时只设置no-store时的缓存问题,那么可以省略Cache-Control: no-cache。
Cache-Control: no-store, must-revalidate
Pragma: no-cache
Expires: 0
如果你不关心IE6也不关心HTTP 1.0客户端(HTTP 1.1是在1997年引入的),那么可以省略Pragma。
Cache-Control: no-store, must-revalidate
Expires: 0
如果你也不关心HTTP 1.0代理,那么可以省略Expires。
Cache-Control: no-store, must-revalidate
另一方面,如果服务器自动包含一个有效的Date头部,那么理论上你也可以省略Cache-Control,只依赖Expires。
Date: Wed, 24 Aug 2016 18:32:02 GMT
Expires: 0
但如果最终用户操作了操作系统日期,并且客户端软件依赖于这个日期,那么这可能会失败。
若何设置它们
使用ASP.NET-MVC:
Response.Cache.SetCacheability(HttpCacheability.NoCache); // HTTP 1.1.
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
Response.AppendHeader("Expires", "0"); // Proxies.
使用ASP.NET Web API:
// response 是 System.Net.Http.HttpResponseMessage 的一个实例
response.Headers.CacheControl = new CacheControlHeaderValue
{
NoCache = true,
NoStore = true,
MustRevalidate = true
};
response.Headers.Pragma.ParseAdd("no-cache");
// 我们不能直接使用 response.Content.Headers.Expires,因为它只允许设置 DateTimeOffset? 类型的值。
response.Content?.Headers.TryAddWithoutValidation("Expires", 0.ToString());
使用ASP.NET:
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
Response.AppendHeader("Expires", "0"); // Proxies.
使用HTML:
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
HTML元标签与HTTP响应头部
重要的是要明白:
- 当HTML页面通过HTTP连接提供时,如果HTTP响应头部和HTML的
<meta http-equiv>
标签都设置了相同的头部信息,那么HTTP响应头部中的设置将优先于HTML元标签中的设置。 - HTML元标签主要用于当页面通过本地文件系统的file:// URL查看时。在这种情况下,浏览器会参考这些元标签来设置页面的某些属性。
- 如果在编程时没有明确指定HTTP响应头部或HTML元标签,那么Web服务器可能会使用默认值。这可能会导致与预期不符的结果,因此需要注意这一点。
- 为了避免混淆,尤其是对于初学者来说,最好依赖HTTP响应头部来设置页面的属性,而不是HTML元标签。
- 在HTML5中,不是所有的
<meta http-equiv>
标签都是有效的。只有符合HTML5规范中列出的http-equiv值才是被允许的。因此,在使用这些标签时需要特别注意其有效性。
验证实际的HTTP响应头部
您可以通过在Chrome/Firefox/IE中按F12键,然后打开“网络”或“Net”选项卡面板,点击您感兴趣的HTTP请求来查看有关HTTP请求和响应的所有详细信息。以下截图来自Edge:
文件下载设置这些头部信息
尽管可以在文件下载时使用类似的HTTP头部信息来控制缓存行为,但你需要特别小心处理,以避免在某些浏览器(特别是较旧的IE版本)中出现问题。同时,对于文件下载,更好的做法可能是使用版本控制来确保用户获取到的是最新的文件版本,而不是依赖于HTTP头部信息来控制缓存。如果你对这方面知识感兴趣,可以自行检索相关资料,这里就不再赘述。
最后,如果您认为这篇文章为你带来了亿点点收获,麻烦留个小赞再离开吧~