MDN关于缓存的说明
缓存的意义
- 降低服务端压力
- 提升页面访问性能
缓存类型
缓存有有很多种类型,大体可以分为两类
- private 为单个用户缓存的信息,一般通过浏览器缓存支持
- shared 为多个用户缓存的信息,比如ISP供应商会在本地网络建设代理缓存,降低网络延迟和压力
缓存目标
术语
- cache key 假设缓存服务器的存储结构是kv存储,kv -> k
- cache entity kv -> v
一般针对GET请求进行缓存,cacheKey通常是url + method(method一般会省略) 缓存的对象包括
- http code是200,正常返回的结果
- 301永久重定向的资源
- 404
- 206
- 其他非get方法的请求结果,前提是定义过cache key(比较少见) 假设设置了vary,会有次要key,将返回的数据进行更细粒度的缓存。
缓存控制
- 不缓存
每次请求都需要返回实时结果。cache-control: no-store
场景:比如接入第三方服务校验SSO,鉴权在访问链路中的一环。每次访问该页面时都需要校验登录状态,则此页面需要设置禁止缓存。
- 每次都走协商缓存
可以缓存页面,但取缓存之前需要进行校验(走协商缓存),考虑这个设置cache-control: no-cache
可以达到一样效果。cache-control: max-age=0, must revalidate
场景:SPA首页,访问时设置no-cache + Etag。需要利用缓存,但同时需要校验缓存可用。
- 缓存时间久
场景:cdn存放的静态文件。immutable用于说明该文件始终不会改变,即使用户显示刷新页面,主要不过期,也不会走协商缓存。cache-control: public, max-age=604800, immutable
- private 和 public cache
public表示所有请求链路上所有的缓存服务器都可以缓存,private只允许浏览器对个人用户的数据进行缓存。Cache-Control: private Cache-Control: public
- 过期时间限制
场景:设置强制缓存的失效时间,会覆盖Expire头设置的值。在max-age时间内会直接返回强制缓存,超期进行协商缓存。Cache-Control: max-age=31536000
校验设置
Cache-Control: must-revalidate
每次都走一遍协商缓存,确认缓存时间是否超期。与max-age配合使用。
Pragma pragma是http/1.0的header, 是cache-control不支持的降级方案。
缓存有效性(freshness)
为什么需要判定缓存的有效性?
- 缓存服务存储空间有限,需要有一定的回收策略(cache eviction)
- 被缓存的资源也需要适时更新
- http协议是客户端-服务器协议(是基于客户端收发请求制定的协议),当服务器上的资源更新时,无法主动通知到客户端,所以双方需要提前确认好资源的过期时间
概念
- fresh 资源没有过期时的状态
- stale 资源超出了过期时间的状态
回收策略会优先存储fresh状态资源,但stale资源也不会被马上回收,如果被访问到了,会再次确认该缓存的状态(校验过程,走协商缓存)是否fresh,如果返回304,可以继续缓存,节约带宽。
freshness lifetime(缓存状态为fresh的资源,存在的生命周期时间)受几个因素影响,
- 首先看cache-control是否有Max-age,max-age=N,则lifetime -> N
- 没有的话,看有无Expires头,有的话,与Date头相减
启发式检查
当服务器未指定freshness相关的头部字段,如cache-control,Expire时,缓存服务会通过启发式算法尝试进行freshness的判定。
这种情况下会查看last-modify
字段,如果有的话,会进行如下设置。(原则上对于每个请求都希望尽可能进行缓存,此处假设文件修改到获取的时间越久,freshLifeTime应该越大,但又应该小于未修改的这段时间。eg. 4点获取文件,上次修改时间为3点,则lifetime为6分钟)
(DateTime - LastModifiedTime) / 10
具体可参考 RFC说明(注:说明中还提出,如果url带?,禁止缓存)
更新资源
针对部分资源需要更可能更新(如spa index.html页面),部分资源需要缓存(如js,css等静态资源)的情况,提出了如下版本管理方案
缓存检验(协商缓存)
缓存超过过期时间后,状态变为stale,需要重新校验才能知道缓存状态是否真的过期了。 检验分为
- strong validation 如果response有Etag,用If-None-Match头向服务器端发起验证。
- weak validation 如果reponse有Last-Modified字段,向服务器端发起带If-Modified-Since的请求。
如果文件未改变,会返回304。改变会重新获取新的文件,返回200 + 文件内容。
协商缓存触发时机是用户点击reload,或者response设置的值是cache-control: must-revalidate
不同的返回数据
如果有vary字段,则会根据不同的字段,缓存进行更细粒度的处理。
场景:响应式页面用同一个url,为避免pc缓存移动端页面数据可以设置
vary: user-agent
。这样就可以为不同的user-agent返回对应的缓存结果。
还需注意,因为vary头的结果字段是严格相等,意味着,假设设置了vary: Accept-Encoding
, 而request的accept-Encoding: gzip,deflate,sdch, Accept-Encoding: gzip,deflate, Accept-Encoding: gzip
是不同的缓存key,会缓存多份。即使response的Content-Encoding
都是gzip也没用。所以缓存服务器需要做一下处理,只保留需要的accept-Encoding
。
QA
- memory cache, disk cache, service worker, push cache什么时候用什么cache?why
- 先找memory cache,如果找不到,再找disk cache。如官网页面公共资源,如果新开页面,资源from memory cache,或者回退。disk cache,memory找不到再找disk。 service worker (todo), push cache (todo)
- 如果不设置cache-control,只有Date头,缓存策略是怎样的? 如果是Date + Etag又是怎样的?
- 为什么last-modified是弱校验?
- 因为1s问题,last-modified返回时间精确到s,不是非常准确
- Etag的W是什么意思
- weak comparison,比较文件时,只比较内容,不比较作者变更等元信息
- max-age=60; 与max-age=60, must-revalidate有什么区别?
- must-revalidate是stale时再校验,此处为age > 60,与前者区别在于,当状态stale, origin server 未正常响应(如502或者504)时,前者会使用缓存,后者不会。原则上must-revalidate用来保障一定收到服务器端的200或者304再来决定是否使用缓存。
Note
- 强缓存和协商缓存怎么理解
- 协商缓存, negotiation content, cache validation,指的是有缓存的基础上,校验是否可用的过程。强缓存指缓存没过期,直接使用。
Comments
暂不支持评论,如有问题,请发邮件至baiyang.feng@outlook.com。 望不吝赐教~