新鲜度
理论上来讲,当一个资源被缓存存储后,该资源应该可以被永久存储在缓存中。由于缓存只有有限的空间用于存储资源副本,所以缓存会定期地将一些副本删除,这个过程叫做缓存驱逐。另一方面,当服务器上面的资源进行了更新,那么缓存中的对应资源也应该被更新,由于HTTP是C/S模式的协议,服务器更新一个资源时,不可能直接通知客户端更新缓存,所以双方必须为该资源约定一个过期时间,在该过期时间之前,该资源(缓存副本)就是新鲜的,当过了过期时间后,该资源(缓存副本)则变为陈旧的。
驱逐算法用于将陈旧的资源(缓存副本)替换为新鲜的,注意,一个陈旧的资源(缓存副本)是不会直接被清除或忽略的,当客户端发起一个请求时,缓存检索到已有一个对应的陈旧资源(缓存副本),则缓存会先将此请求附加一个If-None-Match头,然后发给目标服务器,以此来检查该资源副本是否是依然还是算新鲜的,若服务器返回了 304 (Not Modified)(该响应不会有带有实体信息),则表示此资源副本是新鲜的,这样一来,可以节省一些带宽。若服务器通过 If-None-Match 或 If-Modified-Since判断后发现已过期,那么会带有该资源的实体内容返回。
下面是上述缓存处理过程的一个图示:
对于含有特定头信息的请求,会去计算缓存寿命。比如Cache-control: max-age=N的头,相应的缓存的寿命就是N。
通常情况下,对于不含这个属性的请求则会去查看是否包含Expires属性,通过比较Expires的值和头里面Date属性的值来判断是否缓存还有效。如果max-age和expires属性都没有,找找头里的Last-Modified信息。如果有,缓存的寿命就等于头里面Date的值减去Last-Modified的值除以10(注:根据rfc2626其实也就是乘以10%)。
缓存失效时间计算公式如下:
expirationTime = responseTime + freshnessLifetime - currentAge
上式中,responseTime
表示浏览器接收到此响应的那个时间点。
Cache-Control
Cache-Control 可以由多个字段组合而成,主要有以下几个取值:
1. max-age 指定一个时间长度,在这个时间段内缓存是有效的,单位是s。例如设置 Cache-Control:max-age=31536000,也就是说缓存有效期为(31536000 / 24 / 60 * 60)天,第一次访问这个资源的时候,服务器端也返回了 Expires 字段,并且过期时间是一年后。
在没有禁用缓存并且没有超过有效时间的情况下,再次访问这个资源就命中了缓存,不会向服务器请求资源而是直接从浏览器缓存中取。
判断缓存是否过期
为什么要预估缓存时间?
55%的请求没有携带max-age,也就是没有告诉客户端这个资源要不要缓存。
有些内容是不怎么相对变化的,比如图片,比如js css这些,但是服务器配置这些有问题,没有考虑到带宽的优化,体验性的提升,所以没有配置描述缓存过期时间的内容。
浏览器有默认缓存时间。
常见的预估时间
• RFC7234 推荐:(DownloadTime– LastModified)*10%
浏览器获取到响应的时间,lastmodify就是服务器端显示的就是上次资源修改的时间。这两个时间相减*10%。
浏览器端缓存无请求
expire 在浏览器端验证expire是否大于当前时间,若大于则不发送http请求,直接cache返回,F5强刷会绕过
Expires: Sun, 10 Feb 2002 16:00:00 GMT
max-age 与expire功能类似,记录的是一个时间长度(秒)。Expires在HTTP/1.0生效,Cache-Control:max-age在HTTP/1.1生效。max-age支持的情况下,优先级高于expire,expire值不生效。
Cache-control: max-age=5
Age 头部及 current_age 的计算
• Age 表示自源服务器发出响应(或者验证过期缓存,最初生成响应的时间),到使用缓存的响应发出时经过的秒数