02月15, 2021

http缓存笔记

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。需要利用缓存,但同时需要校验缓存可用。

  • 缓存时间久
    cache-control: public, max-age=604800, immutable
    
    场景:cdn存放的静态文件。immutable用于说明该文件始终不会改变,即使用户显示刷新页面,主要不过期,也不会走协商缓存。
  • private 和 public cache
    Cache-Control: private
    Cache-Control: public
    
    public表示所有请求链路上所有的缓存服务器都可以缓存,private只允许浏览器对个人用户的数据进行缓存。
  • 过期时间限制
    Cache-Control: max-age=31536000
    
    场景:设置强制缓存的失效时间,会覆盖Expire头设置的值。在max-age时间内会直接返回强制缓存,超期进行协商缓存。
  • 校验设置

    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的资源,存在的生命周期时间)受几个因素影响,

  1. 首先看cache-control是否有Max-age,max-age=N,则lifetime -> N
  2. 没有的话,看有无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

  1. 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)
  2. 如果不设置cache-control,只有Date头,缓存策略是怎样的? 如果是Date + Etag又是怎样的?
  3. 为什么last-modified是弱校验?
    • 因为1s问题,last-modified返回时间精确到s,不是非常准确
  4. Etag的W是什么意思
    • weak comparison,比较文件时,只比较内容,不比较作者变更等元信息
  5. max-age=60; 与max-age=60, must-revalidate有什么区别?
    • must-revalidate是stale时再校验,此处为age > 60,与前者区别在于,当状态stale, origin server 未正常响应(如502或者504)时,前者会使用缓存,后者不会。原则上must-revalidate用来保障一定收到服务器端的200或者304再来决定是否使用缓存。

Note

  1. 强缓存和协商缓存怎么理解
    • 协商缓存, negotiation content, cache validation,指的是有缓存的基础上,校验是否可用的过程。强缓存指缓存没过期,直接使用。

Refs

  1. https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
  2. https://tools.ietf.org/html/rfc7234
  3. https://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/

本文链接:http://fengbaiyang.cn/post/http-caching.html

-- EOF --

Comments

暂不支持评论,如有问题,请发邮件至baiyang.feng@outlook.com。 望不吝赐教~