缓存与内容协商
Contents
缓存和内容协商又称强缓存
(有效期内的缓存)和弱缓存
(服务器和浏览器商量是否能缓存的方案)
1 HTTP缓存
- 例如我们访问百度,百度会发送html文件到客户端,而其他的js、css或图片等文件是由
CDN
发送给客户端的,并且在响应头添加Cache-Control: public, max-age=3600, must-revalidate
,允许客户端缓存该文件。
2 Cache-Control释义
|
|
3 HTTP内容协商
- 协商的是缓存过期后能不能重用的问题
- 过程:
- 客户端第一次向CDN服务器请求js文件时,CDN服务器会在响应头上添加Cache-Control字段以及ETag字段。
- Etag字段值为该js文件编码(md5)后的哈希值字符串
- 浏览器会将该js文件缓存,当缓存过期时,会向服务器发送协商请求,该请求头需要添加
If-None-Match
,其值为之前ETag的值。 - 这样以来,服务器会对比自己的和协商请求头中的ETag值,进而得出缓存文件的处理方式:
- 如果两次值不同,说明服务器端更新了该js文件,所以将以200状态码向客户端响应新的文件,告知浏览器将原来的缓存文件删除或覆盖;
- 如果两次ETag值相同,说明不需要更新js文件,所以将以304状态码向客户端响应,告知客户端沿用缓存文件即可。
4 缓存方案
http协议版本 | 缓存(强缓存) | 内容协商(弱缓存) | 备注 |
---|---|---|---|
HTTP/1.1 | 服务器响应时在响应头添加:Cache-Control: max-age:3600,must-revalidate ETag: ... |
请求头:If-None-Match: ...ETag 响应:304+空内容/200+新内容 |
主流 |
HTTP/1.0 | 服务器响应时在响应头添加:Expire: 时间点A Last-Modified: 时间点B |
请求头:If-Modified-Since: 时间点B 响应:304+空内容/200+新内容 |
依赖于收发双方的时间统一,如果用户PC时间不准确,将会影响缓存文件的时效性。 |
实际工作中,程序员可能会同时使用这两套方案,以兼容一些旧的网络设备和浏览器。
5 禁用缓存
- 服务端要求禁用缓存:
|
|
- 浏览器端禁用缓存:
|
|
6 实际应用
- index.html不能缓存,响应头里加
Cache-Control: max-age=0
防止缓存,加Etag
用于内容协商,加Expire: 过去的时间
用于兼容旧浏览器 - CSS、JS和图片文件一律在文件名后面加版本字符串,如
index-855fcfd82e.js
,响应头里加Cache-Control: max-age=2592000
缓存一个月以上,Etag可以不加(因为内容不会变,过时的缓存可以用)。CDN服务商一般都会帮你做这些事。 - 当CSS、JS和图片文件内容有变化时,直接修改文件名中的版本字符串(Webpack 会帮我们做),替换index.html里的旧文件名即可。旧文件的缓存会一直躺在用户的电脑里直到过期后被浏览器自动清理。
- API响应头里加
Cache-Control: no-store, max-age=0
防止缓存和内容协商。
7 缓存API
- 前端程序员一直在尝试自己用 JS 控制缓存,而不是用 HTTP 缓存。 比如曾经有人通过 AJAX 获取 CSS、JS,然后插入页面中,并存储在 LocalStorage 里作为缓存。其优点是在移动端网速特别慢时(比如 2G/3G 网络),读取 LocalStorage 比内容协商要快很多。 再加上有一段时间浏览器厂商宣传「Web 可以比原生应用相媲美」,于是浏览器专门给JS提供了 一套用于缓存的API:
Cache API
。样例代码如下:
|
|
- 实际工作中,经常将
Cache API
与service worker
结合使用,因为service worker
可以劫持浏览器的请求,并进行响应;而Cache API
可以对该请求的缓存进行增删改查。 注意,第一次请求是无法被劫持的,因为那时JS还没有被下载到浏览器中。但是随后的所有请求都可以被service worker劫持。
Author gsemir
LastMod 2021-11-11