Http 缓存:基本工作原理
Http 缓存是解决 http1.1 协议性能问题的一个主要手段。缓存即有可能存在于浏览器中,也可能存在于服务器中。
Http 缓存的主要原理是为当前请求复用之前请求的响应,其主要目标是降低时延、降低带宽的消耗。
Http 缓存的基本交互流程
下图以 4 个 Case 说明 Browser 向 Server 获取 a.png 这个资源的几种 Cache 交互场景。
- 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 获取。第一次访问如下所示:
这里看到 Size 这个字段是这个资源实际的大小,表示没有使用缓存,接下来刷新页面,使用缓存,注意这个字段的变化:
这里显示了使用缓存的情况,有两种情况,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
参数,会发现它没有返回图片文件。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于