起因
最近在重新看网络缓存相关的内容,找了一个公司的项目,发现该项目测试环境的资源请求都是没有配置 Cache-Control 和 Expires, 但诡异的发现,所有请求的状态码都是 200 OK (from memory cache), 这一刻我的缓存世界观崩塌了!!!
思考
一直以来,我都认为,网络缓存这块,Cache-Control 和 Expires 控制强缓存,Etag 和 Last-Modified控制协商缓存, 浏览器发送请求前会检查缓存是否命中, 现在这里没有配置 Cache-Control 和 Expires, 但响应码却是 200 OK (from memory cache), 命中了强缓存,这里面肯定存在一个我不知道的缓存机制在发挥着作用,于是我开始查找资料,一个东西逐渐浮出水面,它就是 启发式缓存(Heuristic Caching)。
启发式缓存
浏览器会根据响应中的其他信息(如
Last-Modified头部)计算一个 "合理" 的缓存时间。例如,若响应包含Last-Modified,浏览器可能会推测缓存有效期为该时间到当前时间间隔的 10%(不同浏览器算法可能不同)。
回到标题的问题,http 协议层面的确是只有强缓存,协商缓存,但浏览器却自己实现了一个启发缓存, 用于兜底没有配置Cache-Control 和 Expires的情况, 整个缓存查找流程是这样的:
| Cache-Control | Expires | Last-Modified | ETag | 使用缓存 |
|---|---|---|---|---|
| 有 | - | - | - | 强缓存 |
| 无 | 有 | - | - | 强缓存 |
| 无 | 无 | 有 | - | 启发式缓存 |
| 无 | 无 | 无 | 有 | 协商缓存 |
| 无 | 无 | 无 | 无 | 不使用缓存 |
转折
了解启发式缓存之后,我心中的疑惑总算是解决了,但突然发现 index.html 的状态码却不是200 OK (from memory cache),而是 304 Not Modified,它命中的是协商缓存!!! 服啦, 又来一个坑,我把两个请求的响应头拉出来对比发现并没有什么不同,但在请求头发现了猫腻:
如图所示,我发现 index.html 的请求头中配置了 Cache-Control,这是浏览器的默认行为,这就导致浏览器跳过了强缓存、启发式缓存的阶段,直接向服务器发送缓存验证(协商缓存),另外我们在浏览器控制面板勾选 Disable Cache,其实就是设置了请求头中的 Cache-Control 为 no-cache, 这时候浏览器的行为是不使用任何缓存(与响应头设置Cache-Control 为 no-cache不一致)。
总结
缓存这块真的坑很多,不仅仅是背点八股就行的,实践才能出真知啊! 当然,以上都是我个人测试得到的结论,如有异议,可在评论区指正,以上!