强缓存&协商缓存

145 阅读6分钟

背景:node+express环境下,设置相关接口的缓存(协商缓存&强缓存)

Cache-Control

通用消息头字段,被用于在http请求和响应中,通过指定指令来实现缓存机制。

语法:

  • 不区分大小写,建议小写。
  • 多个指令以逗号分隔。
  • 具有可选参数,可以用令牌或者引号的字符串语法。

其他:

  • 200 from memory cache 不请求服务器,从内存中读取之前加载过并缓存下来的资源,页面关闭时,资源就会被内存释放。
  • 200 from disk cache 不请求服务器,从磁盘中读取之前已经加载过的资源,页面关闭不会被释放,除非用户手动清理。

max-age= (强缓存相关设置)

相对时间,设置缓存存储的最大周期,超过这个时间缓存被认为过期 (单位秒)。与Expires相反,时间是相对于请求的时间。

image.png 设置了20秒后过期。如果没有超过这个时间,简单刷新,就是200 (disk cache) ,超过了,会向服务器发起请求,资源没更新,触发协商缓存返回状态码304,再简单刷新,就是 200 (disk cache) ,若超过时间且资源更新了,就是200

image.png

image.png

设置了很长时间,但是服务器更新了,还会简单刷新还会更新吗? 不会!如下图,设置了一年,服务器更新了接口信息,简单刷新,仍然只拿到了旧的数据,除非用户强制刷新,才能获取到最新的数据。因此,为了避免数据资源来不及更新,尽量使用协商缓存或者max-age=0, must-revalidate

image.png image.png
万一真不小心设置了强缓存,又需要更新怎么办?

  • 改接口路径:前后端同时改路径,或者前端添加请求随机数,修改缓存命中方式。

max-stale[=<seconds>]

指定时间内, 即使缓存过时, 资源依然有效

min-fresh=<seconds>

指定时间内都是保持新鲜度,也就是每一次都要从服务器端请求,状态码 200 ok 过了这段时间后,就是可以采用默认的协商缓存

no-cache

允许客户端存储文件,但是每次使用之前都必须请求服务器校验缓存的文件是否还在有效期内,如果还在,直接使用缓存,返回状态码 304 ,否则使用服务器最新的文件,返回200 okimage.png 简单刷新:服务器资源无更新的情况下,简单刷新返回状态码 304,如果强制刷新了,那么相当于初次请求,返回200

image.png
尝试在接口中返回多一组数据,并进行简单刷新

image.png 由于接口数据更新了,简单刷新,会重新向服务器请求校验了一次缓存有效性,缓存被服务器判断失效了,重新获取最新的资源,所以就会返回状态码 200

image.png

image.png 注意,no-cache优先级比max-age高

no-store

不使用缓存 客户端不需要存储有关客户端或服务器响应的任何内容,每次请求都会重新请求服务器,状态码始终是200

  router.get("/", function (req, res, next) {
  res.setHeader("Cache-Control", "no-store");
  res.send([
    {
      name: "home",
      path: "/home",
      component: "home",
    },
    {
      name: "demo",
      path: "/demo",
      component: "demo",
    },
  ]);
});

如下图,初次请求后,再请求这个接口,不会走协商缓存(get请求默认会走协商缓存,再次刷新,状态码304),而设置no-store后,就是代表不需要缓存了,再次刷新后都是200 ok,一般需要尽量多的合理的缓存,有助于节省带宽

image.png

public

表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,即使是通常不可缓存的内容。(例如:1.该响应没有max-age指令或Expires消息头;2. 该响应对应的请求方法是 POST 。)类似于要买国外的商品(获取数据),这类商品可以从代购购买(代理服务器),不需要一定从源头发货(目标服务器),这样更省时、省力。

private

表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。私有缓存可以缓存响应内容,比如:对应用户的本地浏览器。类似于要买国外的商品(获取数据),这类商品禁止从代购购买(代理服务器),只能从源头发货(目标服务器),禁止中间代购,这样就可以自己囤货(私有缓存)。

s-maxage=<second>

同max-age,但是仅用于共享缓存(代理缓存托管缓存),如CDN缓存

proxy-revalidate

与 must-revalidate 作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略。

no-transform

强制要求代理服务器不要对资源进行转换, 禁止代理服务器对 Content-Encoding, Content-Range, Content-Type字段的修改(因此代理的gzip压缩将不被允许)

only-if-cached

仅返回已经缓存的资源,不再向服务器获取新的内容。若无缓存则返回504

must-revalidate

使用缓存资源之前,必须先验证状态,并且过期资源不应该再使用。

Last-Modified、if-modified-since

  • 与协商缓存相关的设置
  • last-modified 表示该文件上一次被修改的时间,精确到秒
  • if-modified-since 上一次请求的 last-modifed值,精确到秒

Etag、if-none-match

  • 与协商缓存相关的设置
  • Etag 表示文件的唯一标识:由于 Last-Modified只能精确到,1毫秒也能够修改很多东西了,可能会不准确,每次修改过文件了,都会重新生成新的Etag
  • if-none-match 上一次请求的Etag,初次请求后,再次发起请求,浏览器会将上一次请求的Etag发送回去,用来进行对比。
  • 同时使用last-modifiedetag是可以一起使用的,服务器会优先验证etag,一致的情况下,才会继续比对last-modified,都没改变就返回304

image.png

Expires (与强缓存相关的设置)

绝对的过期时间,响应头包含日期/时间,即在此时候之后,响应过期,格式如expires: Mon, 29 Mar 2021 01:03:05 GMT,存在的问题:

  • 强缓存的判断是经过客户端判断的,假设客户端的时间被用户修改了,那么Expires会无法做出正确的判断。

其他

  • 优先级no-cache >max-age> (CacheControl相关设置)>Expires > ETag > Last-Modified

  • 优先判断是否命中强缓存(强缓存和协商缓存的主要区别:是否需要请求服务器),与强缓存相关的配置 ExpiresCacheControl,与协商缓存相关的配置Etag、if-none-match、Last-Modified、if-modified-since