HTTP缓存

本文最后更新于:8 个月前

本文介绍了http缓存的工作流程,强缓存、协商缓存的工作机制和重要字段。以及介绍了「代理缓存&本地缓存」、「下行缓存&上行缓存」、「内存缓存&磁盘缓存」的概念

HTTP缓存

http缓存机制分为强缓存、协商缓存两种

  1. 强缓存,判断缓存中的资源是否过期,没有过期,直接获取缓存资源;否则请求服务器资源
  2. 协商缓存,通过在请求中携带特殊字段(If-Modified-Since或If-None-Match)向服务器询问缓存中的资源是否发生改变,没有改变,重定向到缓存获取缓存中的资源;如果改变了,请求服务器的资源

http两种缓存的工作流程

img

一、强缓存

利用http头中的Expires(http1.0)Cache-Control(http1.1)两个字段来控制的。强缓存中,当请求再次发出时,浏览器会根据其中的Expires和Cache-Control判断目标资源是否“命中”强缓存,如果命中则直接从缓存中获取资源,不会再与服务端发生通信。命中强缓存的情况下,返回的HTTP状态码为200。

如下图中,返回的是 200 状态码,但在 size 项中标识的是 from disk cache,就是使用了强制缓存

img
  • Cache-Control(http1.1), 是一个相对时间;

  • Expires(http1.0),是一个绝对时间;

  • 优先级: Cache-Control > Expires

expires是HTTP1.0的产物。当服务器返回响应时,在Response Headers中将过期时间写入Expires字段。浏览器通过对比本地时间和过期时间,判断资源是否过期。

Cache-Control是HTTP1.1提出的特性。

Cache-Control包含的值很多:

说明
public 表明响应可以被任何对象(包括:发送请求的客户端、代理服务器等等)缓存
private 表明响应只能被客户端缓存
no-cache 跳过强缓存,直接进入协商缓存阶段
no-store 表示当前请求资源禁用缓存
max-age= 设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)
s-maxage= 覆盖max-age或者Expires头。如果s-maxage未过期,则向代理服务器请求其缓存内容。

这里需要注意的是:s-maxage仅在代理服务器中生效,客户端只需要考虑max-age。

  • 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
  • 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
  • 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control

二、协商缓存

协商缓存,也称为对比缓存。协商缓存机制下,浏览器需要向服务器去询问缓存的相关信息,进而判断是重新发起请求、下载完整的响应,还是从本地获取缓存的资源。

如果服务端提示缓存资源未改动(Not Modified),资源会被重定向到浏览器缓存,这种情况下网络请求对应的状态码是 304(如下图)。

img

控制协商缓存的字段分别有:Last-Modified和Etag,其中Etag的优先级比Last-Modified高

方式一:Last-Modified + If-Modified-Since

  • 服务器返回资源时,在响应头附上 Last-Modified字段,表示资源的最后修改时间
  • 客户端发送请求时,当资源过期后,如果发现响应头中有Last-Modified声明(一个时间戳),则发送请求时,通过If-Modified-Since携带上这个时间戳,与服务器上的资源的Last-Modified字段进行对比
  • 如果资源被修改了,返回新资源;如果没有新修改,返回304状态码

Last-Modified(Response Header)和If-Modified-Since(Request Header)是一对报文头,属于HTTP1.0。

Last-Modified表示资源的最后修改时间,是一个时间戳,如果启用了协商缓存,它会在首次请求时随着Response Headers返回。

1
Last-Modified: Sat, 09 May 2020 09:33:56 GMT

If-Modified-Since是一个请求首部字段,并且只能用在GET或HEAD请求中。客户端再次请求服务器时,请求头会包含这个字段,后面跟着在缓存中获取的资源的最后修改时间。

1
If-Modified-Since: Sat, 09 May 2020 09:33:56 GMT

服务端收到请求发现此请求头中有If-Modified-Since字段,会与被请求资源的最后修改时间进行对比,如果一致则会返回304和响应报文头,浏览器从缓存中获取数据即可。从字面上看,就是说从某个时间节点开始看,是否被修改了,如果被修改了,就返回整个数据和200 OK,如果没有被修改,服务端只要返回响应头报文,304 Not Modified,Response Headers不会再添加Last-Modified字段。

方式二:Etag + If-None-Match

Etag是一个响应首部字段,是根据实体内容生成的一段hash字符串,标识资源的状态,由服务端产生。

1
ETag: W/"324023994867772d0dd9fac01f1420bd"

If-None-Match是一个条件式的请求首部,如果请求资源时在请求首部加上这个字段,值为之前服务器返回的Etag,则当且仅当服务器上没有任务资源的Etag属性值与这个值相符,服务器才会返回带有请求资源实体的200响应,否正服务器会返回不带实体的304响应。

1
If-None-Match: W/"324023994867772d0dd9fac01f1420bd"

Etag 的生成过程需要服务器额外付出开销,会影响服务端的性能,这是它的弊端。Etag 并不能替代 Last-Modified,它只能作为 Last-Modified 的补充和强化存在

优先级:Etag > Last-Modified

如果在第一次请求资源的时候,服务端返回的 HTTP 响应头部同时有 Etag 和 Last-Modified 字段,那么客户端再下一次请求的时候,如果带上了 ETag 和 Last-Modified 字段信息给服务端,

这时,服务端先会判断 Etag 是否变化了,如果 Etag 有变化就不用在判断 Last-Modified 了,如果 Etag 没有变化,然后再看 Last-Modified。

顺序:先强制,再协商

协商缓存这两个字段都需要配合强制缓存中 Cache-control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求

img

例如:使用 ETag 字段实现的协商缓存的过程:

  • 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 ETag 唯一标识,这个唯一标识的值是根据当前请求的资源生成的;

  • 当浏览器再次请求访问服务器中的该资源时,首先会先检查强制缓存是否过期:

    • 如果没有过期,则直接使用本地缓存;
    • 如果缓存过期了,会在 Request 头部加上 If-None-Match 字段,该字段的值就是 ETag 唯一标识;
  • 服务器再次收到请求后,

    会根据请求中的 If-None-Match 值与当前请求的资源生成的唯一标识进行比较

    • 如果值相等,则返回 304 Not Modified,不会返回资源
    • 如果不相等,则返回 200 状态码和返回资源,并在 Response 头部加上新的 ETag 唯一标识;
  • 如果浏览器收到 304 的请求响应状态码,则会从本地缓存中加载资源,否则更新资源。

三、缓存控制字段

1、可缓存性控制

  1. cache:public,表明响应资源可以被所有对象缓存,如浏览器、代理服务器等
  2. cache:private,表明响应资源只能被浏览器缓存
  3. cache:no-cache,跳过强缓存阶段、直接进入协商缓存阶段,即需要向服务器验证缓存有效性
  4. cache:no-store,禁用缓存

2、缓存有效性控制

  1. max-age=秒数,设置缓存储存的最大期限,超过这个时间表示缓存过期
  2. s-maxage=秒数,和max-age相同的作用,只不过仅仅适用于代理服务器
  3. max-stale[=秒数],(在请求头中添加),表示浏览器愿意接受一个过期的缓存资源,可以选择添加时间,表示愿意接受的范围
  4. min-fresh=秒数,(在请求头中添加),表示客户端希望获取一个能在指定的秒数内保持其最新状态的响应
  5. stale-while-revalidate=, 表明客户端愿意接受陈旧的响应,同时在后台异步检查新的响应。秒值指示客户愿意接受陈旧响应的时间长度。
  6. stale-if-error=,表示如果新的检查失败,则客户愿意接受陈旧的响应。秒数值表示客户在初始到期后愿意接受陈旧响应的时间。

3、重新加载 / 验证控制

  1. must-revalidate,一旦资源过期(比如已经超过max-age),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求。
  2. proxy-revalidate,与must-revalidate作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略

4、其它控制

  1. no-transform,(响应头中使用),不得对资源进行转换或转变,一般用于限制代理服务器
  2. only-if-cached,(请求头中使用),表明客户端只接受已缓存的响应,并且不要向原始服务器检查是否有更新的拷贝

5、组合控制

cache-control可以同时接受多个取值的。可缓存性控制+缓存有效性控制+其他控制 ,这几个控制维度是不冲突的,可以共同实现缓存的实现方式限定。

当不同字段发生冲突时,按照优先级进行取舍

四、代理服务器缓存 & 本地缓存

代理服务器缓存,就是保存在代理服务器上的缓存资源,可以减少直接请求源服务器造成的压力

本地缓存,就是保存在浏览器本地的缓存资源,在减少服务器压力的基础上,还可以提高资源加载速度,优化用户体验

设置为cache-control:public,代理服务器和浏览器客户端都可以缓存资源;设置为cache-control:private,只有浏览器客户端可以缓存资源。

五、下行缓存 & 上行缓存

下行缓存,就是通过在响应头设置cache-control缓存控制字段,即在nginx或者其它代理上设置控制字段。

上行缓存,就是在http请求头中设置缓存控制字段,一般用的较少。

六、内存缓存 & 磁盘缓存

根据缓存存放位置,可以分为:「Memory cache」内存缓存、「Disk cache」硬盘缓存

1、内存缓存的特点

  • 读取速度快
  • 一旦关闭Tab页、或者关闭浏览器,内存就会被释放
image-20221122153105075

2、硬盘缓存的特点

  • 读取速度慢一点
  • 储存时间长
image-20221122153232285

Q:怎么去区分一个资源是该缓存到内存中、还是缓存到硬盘中呢?

3、储存形式

以上两者的存储形式为一个index.dat文件,记录存储数据的url,然后再分别存储该url的response信息和content内容。

Response信息最大作用就是用于判断服务器上该url的content内容是否被修改。

参考文章

一文彻底掌握HTTP缓存 - 知乎 (zhihu.com)

3.1 HTTP 常见面试题 | 小林coding (xiaolincoding.com)

HTTP缓存协议实战 - 掘金 (juejin.cn)


HTTP缓存
http://timegogo.top/2022/10/31/HTTP/HTTP缓存/
作者
丘智聪
发布于
2022年10月31日
更新于
2023年7月16日
许可协议