关于浏览器缓存的小结。
浏览器收到服务器的响应后,会检查响应头信息,一般用于缓存相关的头信息有 4 个:
- ETag
- Cache-Control
- Expires
- Last-Modified
ETag
ETag(Entity Tag)是一个用于缓存校验的 token 字符串,通常以文件的哈希值来表示。
浏览器在文件的响应头中接收到 ETag,当文件过期后,浏览器再次向服务器请求该文件时会附上先前接收到的 ETag;服务器通过对比 ETag 和文件的哈希值判断资源是否变化,如果没有则返回 304,浏览器就知道缓存中的资源是安全的。
**注意:**仅当缓存中的文件过期了,ETag 才会被用在请求中。
Cache-Control
Cache-Control 常用于设置资源的缓存行为、过期时间、验证等。
缓存行为
Cache-Control: public
:资源可以被任意缓存(浏览器、CDN 等)Cache-Control: private
:资源只能被浏览器缓存Cache-Control: no-store
:资源不被缓存,浏览器总是请求服务器获取最新文件Cache-Control: no-cache
:资源被浏览器缓存,但使用前总会先请求服务器检查文件(常用于 html 文件)
过期时间
Cache-Control: max-age=60
:指定资源应该被缓存多少秒Cache-Control: s-max-age=60
:同上,用于中间缓存(CDN 等)Cache-Control: must-revalidate
:资源被使用前必须去验证过期状态
Expires
Expires 来自 http 1.0 时代,该字段指定了一个日期,超过这个日期就代表资源是无效的,如果已经指定了 Cache-Control 中的 max-age,则浏览器就会忽略 expires。
1 | Expires: Wed, 25 Jul 2018 21:00:00 GMT |
Last-Modified
Last-Modified 也是来自 http 1.0 时代,该字段包含了资源最后修改的日期和时间。
1 | Last-Modified: Mon, 12 Dec 2016 14:45:00 GMT |
HTML Meta Tag
在 HTML5 版本之前,在 html 中使用元标签(meta)指定 cache-control 是一个有效的方式
1 | <meta http-equiv="Cache-control" content="no-cache"> |
但在 HTML5 中不推荐这么做,因为只有浏览器可以识别这个标签,中间缓存(CDN)是识别不了的。
HTTP Response
一个简单的 http 响应:
1 | Accept-Ranges: bytes |
- 第 2 行告诉我们 max-age 为 1 小时
- 第 5 行告诉我们这是一个 png 图片资源
- 第 7 行告诉我们 ETag 将在 1 个消失后去验证资源是否改变过
- 第 8 行,Expires 头会被忽略,因为已经设置了 Cache-Control: max-age=3600
- 第 10 行,Last-Modified 头展示了图片资源的最后修改时间
Cache Busting
Cache Busting 会使一个资源文件失效,强制浏览器去服务器端重新获取数据。
我们可以通过改变文件名来命令浏览器去避开缓存,对于浏览器来说,这是一份全新的资源,所以会去请求最新的数据。
版本号
我们可以给资源添加一个版本号。
1 | assets/js/app-v2.min.js |
指纹(fingerpring)
我们可以基于文件内容添加一个指纹值。
1 | assets/js/app-d41d8cd98f00b204e9800998ecf8427e.min.js |
拼接查询参数
我们可以在文件名的末尾拼接一个查询参数。
1 | assets/js/app.min.js?version=2 |
最佳实践
推荐
- 对于静态资源来说,使用 Cache-Control 和 ETag 头部来控制缓存的行为
- 设置一个比较长的 max-age 值,以此来获得浏览器缓存带来的好处
- 针对 Cache Busting,使用指纹值(或 hash 值)和版本号的方式
不推荐
- 使用 html 元标签去指定缓存的行为
- 使用查询参数的方式实现 Cache Busting