Http 缓存 1:基本工作原理

本贴最后更新于 1699 天前,其中的信息可能已经事过境迁

Http 缓存:基本工作原理

Http 缓存是解决 http1.1 协议性能问题的一个主要手段。缓存即有可能存在于浏览器中,也可能存在于服务器中。
Http 缓存的主要原理是为当前请求复用之前请求的响应,其主要目标是降低时延、降低带宽的消耗。

Http 缓存的基本交互流程

下图以 4 个 Case 说明 Browser 向 Server 获取 a.png 这个资源的几种 Cache 交互场景。

HttpCache 原理.png

  • Case1

第一次访问,没有本地缓存,向 Server 发起请求,Server 返回 200 并将 a.png 返回给 Browser,Browser 将 a.png 缓存在本地。

  • Case2

第二次访问,本地已有 a.png 的缓存,不再向 Server 发起请求,直接使用本地缓存。

  • Case3

第三次访问,本地有 a.png 缓存,但本地已过期,向 Server 发起请求,同时会带上本地 a.png 的指纹。此时 Server 会检查 Server 端的 a.png 的指纹是否和 Browser 传过来的相同,如果相同,说明 Server 端没有更改,Server 端会返回 http304,但并不会返回 a.png 给 Browser,让 Browser 继续使用本地的 a.png 即可。

  • Case4

第四次访问,本地有 a.png 缓存,但本地已过期,向 Server 发起请求,同时带上本地 a.png 的指纹。此时 Server 检查 Server 端的 a.png 指纹是否与 Browser 传过来的相同,如果不同,说明 Server 端有更新,Server 端会返回 http200,并返回新的 a.png 给 Browser,Browser 使用新的 a.png 并将本地 cache 更新。

举个栗子

例如我们模拟向我的 blog 站点访问 http://blog.feathers.top/ ,并观察 http://image.feathers.top/image/WechatIMG1.jpeg 这个资源,为了保证第一次不使用本地缓存,用 command + shift + R 强制从 Server 获取。第一次访问如下所示:

HttpCache2.png

这里看到 Size 这个字段是这个资源实际的大小,表示没有使用缓存,接下来刷新页面,使用缓存,注意这个字段的变化:

HttpCache3.png

这里显示了使用缓存的情况,有两种情况,Memory Cache 和 Disk Cache。
如果间隔时间较短刷新页面,再次请求时,因为此时内存中的缓存还没失效,会使用 Memory Cache;
如果内存中的 Cache 存在时间过长,Browser 会将 Cache 缓存在 Disk 中,此时再访问,会使用 Disk Cache。

然后我们模拟一下 Browser 缓存失效的场景。默认情况下,缓存失效时间过长,为了模拟,我们将 WechatIMG1.jpeg 的请求 cURL 复制出来:

curl 'http://image.feathers.top/image/WechatIMG1.jpeg' \
  -H 'Referer: http://blog.feathers.top/' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36' \
  --compressed \
  --insecure -I

在结尾加上 -I,使 cURL 只显示响应头。其响应结果如下:

HTTP/1.1 200 OK
Server: Tengine
Content-Type: image/jpeg
Content-Length: 28340
Connection: keep-alive
Date: Fri, 03 Apr 2020 22:16:19 GMT
Cache-Control: public, max-age=31536000
Etag: "FvMIFM00fGiTlUMzlREabTaxjkVS"
X-M-Log: QNM:xs450;QNM3/304
X-M-Reqid: MFUAAO5R_b0abwIW
X-Qnm-Cache: Hit
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-Log, X-Reqid
Access-Control-Max-Age: 2592000
Content-Disposition: inline; filename="WechatIMG1.jpeg"; filename*=utf-8''WechatIMG1.jpeg
Content-Transfer-Encoding: binary
Last-Modified: Thu, 19 Sep 2019 10:17:01 GMT
X-Log: X-Log
X-Qiniu-Zone: 0
X-Reqid: oM8AAADUIuzZT_IV
X-Svr: IO
Ali-Swift-Global-Savetime: 1583266120
Via: cache10.l2cn2179[0,200-0,H], cache20.l2cn2179[1,0], vcache15.cn1005[0,200-0,H], vcache8.cn1005[2,0]
Age: 1943115
X-Cache: HIT TCP_HIT dirn:10:343300469
X-Swift-SaveTime: Thu, 23 Apr 2020 03:14:44 GMT
X-Swift-CacheTime: 2592000
Timing-Allow-Origin: *
EagleId: b7cb451c15878952940375540e

可以看到,max-age 是个很大的值,那如何模拟 Browser 端缓存失效的场景呢?其实,Browser 在认为缓存失效时,会在请求头加上一个 If-None-Match 头,他的值就是对应资源的标签(或者说指纹,即上面的 Etag 字段),这样 Server 就可以拿这个值和自己的比对,如果相同,说明没有更改,就直接响应一个 304,告诉客户端继续用自己的就行了。下面我们加上这个 Header 模拟一下。

curl 'http://image.feathers.top/image/WechatIMG1.jpeg' \
  -H 'Referer: http://blog.feathers.top/' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36' \
  -H 'If-None-Match: "FvMIFM00fGiTlUMzlREabTaxjkVS"' \
  --compressed \
  --insecure -I

结果如下:

HTTP/1.1 304 Not Modified
Server: Tengine
Content-Type: image/jpeg
Connection: keep-alive
Date: Thu, 02 Apr 2020 05:58:08 GMT
Cache-Control: max-age=4152551
Expires: Wed, 20 May 2020 07:27:19 GMT
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-Log, X-Reqid
Access-Control-Max-Age: 2592000
Content-Disposition: inline; filename="WechatIMG1.jpeg"; filename*=utf-8''WechatIMG1.jpeg
Content-Md5: aLibpZRSi2qRbdP2VjAb3g==
Content-Transfer-Encoding: binary
Etag: "FvMIFM00fGiTlUMzlREabTaxjkVS"
Last-Modified: Thu, 19 Sep 2019 10:17:01 GMT
X-Log: X-Log
X-M-Log: QNM:xs450;QNM3
X-M-Reqid: MFUAAIEPfg8l6wEW
X-Qiniu-Zone: 0
X-Qnm-Cache: Hit
X-Reqid: dA0AAACHK96wuAEW
X-Svr: IO
Ali-Swift-Global-Savetime: 1585807088
Via: cache77.l2cn2270[0,200-0,H], cache67.l2cn2270[80,0], vcache29.cn1015[0,304-0,H], vcache10.cn1015[20,0]
Age: 2093585
X-Cache: HIT TCP_IMS_HIT dirn:0:506046938
Timing-Allow-Origin: *
EagleId: 6f06b41e15879006739354086e

第一行可以发现,Server 直接返回了 304,如果去掉 -I 参数,会发现它没有返回图片文件。

参考

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...