HTTP仅指定Last-Modified和Date的缓存策略

发布 : 2018-12-11 浏览 :

最近一个系统新版本上线之后,有用户反馈接口出现异常, 看了一下发现调用的接口是之前旧版本的, 在新版本中对该接口地址做了修改, 原有的旧接口已经不能使用了。 初步怀疑是缓存设置出了问题。
先去看了一下HTML中引用的资源文件名称是否打了Hash以及Hash新旧版本是否有变化,

1
<script type=text/javascript src=/js/app.946c7f8807ee03c89c4b.js></script>

检查后发现有Hash并且Hash也发生了变化, 但是很明显用户请求到的还是旧的JS文件, 那么基本上可以确定用户端HTML文件发生了缓存, 并且没有正确刷新缓存。
检查了一下index.html的Response Headers

1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200
Server: nginx/1.12.2
Date: Tue, 11 Dec 2018 02:52:51 GMT
Content-Type: text/html
Content-Length: 933
Connection: keep-alive
X-UA-Compatible: IE=11
X-Application-Context: application:prd,env:8080
Last-Modified: Mon, 10 Dec 2018 02:08:46 GMT
Accept-Ranges: bytes
Content-Language: zh-CN

里面并没有指定缓存的Cache-Control、Expires, 缓存相关的字段只有Last-Modified和Date
那么在没有指定Cache-Control和Expires时浏览器使用的缓存方式是怎么样呢?
根据HTTP协议第13.4 Response Cacheability中所说

Unless specifically constrained by a cache-control (section 14.9) directive, a caching system MAY always store a successful response (see section 13.8) as a cache entry, MAY return it without validation if it is fresh, and MAY return it after successful validation. If there is neither a cache validator nor an explicit expiration time associated with a response, we do not expect it to be cached, but certain caches MAY violate this expectation (for example, when little or no network connectivity is available). A client can usually detect that such a response was taken from a cache by comparing the Date header to the current time.

缓存系统 MAY 对一个成功的响应进行缓存, 不同浏览器的做法可能不一样, Chrome的处理方式是

1
(Date - Last-Modified) * 0.1

所以用户访问的时间正好落在了缓存的时间之内, 导致了使用了缓存。
问题的原因找到了, 解决的方案是在HTML的HTTP Response中明确指定Cache-Control或Expires。
另外, 同时还有两个问题

  1. 项目的index.html中http-equiv的meta中明确指定了Cache-Control, 为何没有生效?
1
2
3
<meta http-equiv=pragma content=no-cache>
<meta http-equiv=cache-control content="no-cache, no-store, must-revalidate">
<meta http-equiv=expires content=0>

这个疑问最终在这篇帖子中找到了答案 https://stackoverflow.com/questions/49547/how-to-control-web-page-caching-across-all-browsers

1
2
3
4
5
6
7
8
9
10
11
12
Important to know is that when a HTML page is served over a HTTP connection, 
and a header is present in both the HTTP response headers and the HTML <meta http-equiv>
tags, then the one specified in the HTTP response header will get precedence over the
HTML meta tag. The HTML meta tag will only be used when the page is viewed from local
disk file system via a file:// URL. See also W3 HTML spec chapter 5.2.2.
Take care with this when you don't specify them programmatically,
because the webserver can namely include some default values.

Generally, you'd better just not specify the HTML meta tags to avoid confusion by starters,
and rely on hard HTTP response headers. Moreover,
specifically those <meta http-equiv> tags are invalid in HTML5. Only the http-equiv
values listed in HTML5 specification are allowed.

  1. 为何只有部分用户出现了这个问题

这个问题的主要原因是用户行为会对缓存的策略产生影响, 比如在Chrome中

  • 如果在地址栏中输入URL或者通过书签访问

这个时候 200 OK (from cache) 浏览器发现该资源已经缓存了而且没有过期,没有跟服务器确认,而是直接使用了浏览器缓存的内容。其中响应内容和之前的响应内容一模一样,例如其中的Date时间是上一次响应的时间。

  • F5/点击工具栏中的刷新按钮/右键菜单重新加载
1
2
Cache-Control: max-age=0
If-Modified-Since: Fri, 15 Jul 2016 04:11:51 GMT

其中Cache-Control是Chrome强制加上的,而If-Modified-Since是因为获取该资源的时候包含了Last-Modified头部,浏览器会使用If-Modified-Since头部信息重新发送该时间以确认资源是否需要重新发送。 即使用协商缓存

1
304(Not Modified)

,这样的响应信息很小,所以很快。

  • Ctrl+F5

这个时候直接重新请求, 请求头会被Chrome自动加上

1
2
Cache-Control: no-cache
Pragma: no-cache

本文作者 : Shuai Liang
原文链接 : http://liangshuai.me/2018/12/11/yuque/HTTP仅指定Last-Modified和Date的缓存策略/
版权声明 : 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

知识 & 情怀 | 二者兼得

微信扫一扫, 向我投食

微信扫一扫, 向我投食

支付宝扫一扫, 向我投食

支付宝扫一扫, 向我投食

留下足迹