HTTP缓存策略:强缓存与协商缓存

Posted by Mars at

HTTP缓存: 强缓存与协商缓存

一、HTTP缓存

HTTP缓存针对HTTP响应报文,一般只对GET和HEAD方法响应报文有效。(POST响应在罕见特殊配置下也可以缓存,具体见MDN

HTTP缓存可以存在于浏览器本地,也可以存在于代理服务器。

1. 缓存相关的首部行

1.1 强缓存

优先级从高到低:

Pragma、Cache-Control、Expires

Pragma和Expires都是HTTP1.0的首部。当Pragma设置为no-cache,则意味着每次请求都无法执行强缓存,只能进行协商缓存。

Cache-Control可以设置如下参数:

  • no-cache: 与Pragma一样,每次请求都无法执行强缓存,只能进行协商缓存,但是比Pragma优先级要低;
  • no-store: 不进行缓存。强缓存和协商缓存都不会触发;
  • max-age: 设置缓存相对过期时长;

1. 强缓存

浏览器执行请求时,如果发现本地有之前请求的缓存,先查看请求缓存中的首部行,判断是否命中强缓存:

  1. 如果Cache-Control(优先)存在且设置了max-age值,则计算此次请求的age值ageValue,并与max-age进行比较。如果ageValue>max-age则强缓存触发失败,反之则触发强缓存。

HTTP中缓存的使用期计算(Age Calculation)

HTTP1.1协议要求,当一个响应报文是从缓存里获取的时候,HTTP/1.1协议要求在响应报文中必须添加一个Age首部行。它的值表示的是,从这个响应报文在源服务器中产生或者过期验证的那一刻起,到现在为止所经过时间的一个估计值(从名字上其实就看的出来,它表示的是缓存的年龄)。经常和max-age一起来验证缓存是否过期,即如果这个字段的值比max-age的值还大,那这份缓存就已经过期了。

这个ageValue值的计算,是缓存到达本地时带有的age值initAge,加上这次请求时间点为止,缓存在本地经过的时长agePassed。

age = initAge + agePassed

  1. 如果Cache-Control不存在,但设置了Expires,判断请求的Date是否超过Expires设置的时间,未过期则直接命中强缓存。

Expires: 是GMT格式字符串(绝对值),意味着何时过期,它来自于服务器时间。浏览器在请求进行比较的时候,使用的是系统时间,系统时间可以修改所以相对不可靠。

这时,直接从缓存中读取响应(包含响应头),不与服务器通信。(状态码200)

2. 协商缓存

如果发现 Cache-Control 或 Expires 二者之一有过期,则发送请求到服务器:

如果缓存首部存在Etag,则发送带If-None-Match的请求;(优先级更高)

如果缓存首部存在Last-Modified,则发送带If-Modified-Since的请求。

ETag 与 Last-Modified 的区别?

ETag是服务器根据资源内容,自动生成的唯一的ID。它更能体现资源是否已修改。

Last-Modified主要是有以下三点问题: ① 最短修改时间只能精确到秒;② 有些文件在服务器周期性保存,内容并未修改,这时造成本地缓存的浪费;③ 某些服务器系统不能得到精确的修改时间。

由服务器根据这两个字段判断,缓存是否还可以使用。

如果可以,则意味着协商缓存命中,服务器返回新的响应header信息,但是不带有响应主体。(意味着服务器仍可从缓存中读取响应)(校验码304)

如果校验失败,服务器返回带响应主体的响应报文。(校验码200)

3. 用户行为对缓存的影响

按F5会忽略强缓存,保留协商缓存。

按Ctrl+F5会忽视全部缓存。

4. 如何保证每次资源更新浏览器都会及时更新,防止从缓存读取?

为每一个更新的资源,配置一个独有的资源名。

常用的是在资源后面加上query ID后缀。

Keywords: http
previousPost nextPost
已经有 1000000 个小伙伴看完了这篇推文。