参考文档
深入理解浏览器的缓存机制 https://www.jianshu.com/p/54cc04190252
一文读懂前端缓存 https://mp.weixin.qq.com/s/cUqkG3NETmJbglDXfSf0tg
缓存的分类
- 按存储位置分
- memory cache:
- 存储在内存
- 关闭tab时清空
- 缓存内容太多且没关闭tab时清掉最早的
- 不受http协议头控制
- disk cache:
- 存储在硬盘
- 允许相同资源在跨会话、跨站点情况下使用
- 容量增长后浏览器按照自己的算法计算删除最老的资源
- 受强制缓存策略影响
- memory cache:
- 按失效策略分
- 强制缓存
- 先查看有无缓存,没有的话才请求服务
- 直接减少请求次数
- 策略直接影响disk cache
- 协商缓存
- 强制缓存失效时,使用协商缓存
- 请求服务器,询问缓存是否仍然可用,可用则继续使用,不可用则同时返回新的资源
- 强制缓存
请求头设置规则
- 强制缓存
- Expires:缓存到期时间绝对值,具体日期时间点
- Cache-control:资源最大有效时间,在该时间段内客户端不向服务端发请求
- max-age:即最大有效时间,单位秒
- must-revalidate:如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否还有效。
- no-cache:只避免强制缓存,使用协商缓存,内存缓存有效。也就是说,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,如果资源未被更改,可以避免下载。
- no-store: 真正意义上的“不要缓存”。所有内容都不走缓存,包括内存、强制缓存和协商缓存。
- public:所有的内容都可以被缓存 (包括客户端和代理服务器, 如 CDN)
- private:所有的内容只有客户端才可以缓存,代理服务器不能缓存。默认值。
- 协商缓存
- 响应头Last-Modified & 请求头If-Modified-Since
- 服务器通过 Last-Modified 字段告知客户端,资源最后一次被修改的时间
- 浏览器将这个值和资源内容一起存在缓存中
- 下一次请求相同资源时时,浏览器从自己的缓存中找出“不确定是否过期的”缓存。在请求头中将上次的 Last-Modified 的值写入到请求头的 If-Modified-Since 字段
- 服务器会将 If-Modified-Since 的值与 Last-Modified 字段进行对比。如果相等,则表示未修改,响应 304;反之,则表示修改了,响应 200 状态码,并返回数据
- 响应头Etag & 请求头If-None-Match
- Etag 存储的是文件的特殊标识(一般都是 hash 生成的),服务器存储着文件的 Etag 字段。
- 流程与Last-Modified类似,只是在服务端对比的是文件内容(hash)
- 响应头Last-Modified & 请求头If-Modified-Since
- 缓存优先级
- memory cache > disk cache
- 强制缓存(Cache-control > Expires) > 协商缓存(Etag > Last-Modified)
浏览器处理流程
- 查看memory cache,有则使用memory cache
- 查看disk cache
- 强制缓存未过期:使用强制缓存,状态码200
- 强制缓存已过期:服务端确认缓存是否可用,根据结果判断使用缓存(状态码:304)还是新资源(状态码:200)
- 发送请求,等待响应
- 将响应资源存入disk cache(http协议头允许的情况下)
- 将响应资源存入memory cache(除no-store外,忽略其他http协议头)
如果什么缓存策略都没设置,那么浏览器会怎么处理?
对于这种情况,浏览器会采用一个启发式的算法,通常会取响应头中的 Date 减去 Last-Modified 值的 10% 作为缓存时间。
所谓用户行为对浏览器缓存的影响,指的就是用户在浏览器如何操作时,会触发怎样的缓存策略。主要有 3 种:
- 打开网页,地址栏输入地址: 查找 disk cache 中是否有匹配。如有则使用;如没有则发送网络请求。
- 普通刷新 (F5):因为 TAB 并没有关闭,因此 memory cache 是可用的,会被优先使用(如果匹配的话)。其次才是 disk cache。
- 强制刷新 (Ctrl + F5):浏览器不使用缓存,因此发送的请求头部均带有
Cache-control: no-cache
(为了兼容,还带了Pragma: no-cache
),服务器直接返回 200 和最新内容。
缓存设置方式
- HTML Meta标签控制缓存(非HTTP协议定义)
- 优点:使用上很简单
- 缺点:但只有部分浏览器可以支持(兼容性);所有缓存代理服务器都不支持,因为代理不解析HTML内容本身
- HTTP头信息控制缓存(响应头)
- 使用nginx配置响应头,将缓存策略传递给浏览器及相关缓存代理服务器
缓存策略
对于已有react前端项目现状
- js、css文件
- 每次构建内容改变会修改名称,可以使用强制缓存,修改文件名后发送新请求
- 图片
- 目前项目中图片比较固定,修改小,没有特殊需求可以先使用js、css文件相同策略,变动时修改文件名称
- html
- 所有js、css文件都在html中引用,如果html使用原有文件会出现全套使用老版本的情况,所以html采用不缓存策略(no-store)
- html文件较小,只有js、css等文件的引用,请求资源大小在1-2kb左右,不会产生太多消耗
实例
html文件服务端返回不做缓存策略设置时,以下几种状况下的请求头
ctrl+F5强制刷新
F5刷新