浏览器的启发式缓存到底缓存了多久?

2,719 阅读4分钟

启发式缓存

启发式缓存是浏览器缓存的默认行为(即对于没有 Cache-Control 的响应)不是简单的“不缓存”,而是根据所谓的“启发式缓存”进行隐式缓存。

HTTP 旨在尽可能多地缓存,因此即使没有给出 Cache-Control,如果满足某些条件,响应也会被存储和重用。这称为启发式缓存

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Last-Modified: Tue, 22 Feb 2021 22:22:22 GMT
<!doctype html>

22:22:22 GMT:北京时间比浏览器时间晚8小时

缓存时间

公式为:( Date - Last-Modified ) * 0.1
  • Date:当前请求的时间
  • Last-Modified:服务器中资源最后被修改的日期

MDN:试探性地知道,整整一年没有更新的内容在那之后的一段时间内不会更新。因此,客户端存储此响应(尽管缺少 max-age)并重用它一段时间。复用多长时间取决于实现,但规范建议存储后大约 10%(在本例中为 0.1 年)的时间。

也就是说,如果十天没有更新的资源,会缓存一天的时间,在这段时间内浏览器请求走的都是本地缓存,超出这个时间则向服务器请求资源。

启发式缓存是在 Cache-Control 被广泛采用之前出现的一种解决方法,基本上所有响应都应明确指定 Cache-Control 标头。

彻底理解

这里会比较绕,这个默认缓存的时间到底会缓存多久?是如何进行判断的?

相差较长时间

我们查看一个配置文件的缓存,是没有配置缓存策略的,则默认启发式缓存;

图片.png

再看下该文件响应头中的 DateLast-Modified 信息,这里的这两个时间是决定下次刷新页面之后,是请求服务器还是走本地缓存的关键因素,注意是下一次请求

图片.png

此时当前这一次请求的响应头 (Date - Last-Modified) * 0.1 是决定该文件缓存时间的长短,也就是 (2023-04-13 - 2023-03-09) 等于35天(具体时间时分秒先不计算),再乘以0.1,则当前文件则会缓存大约3.5天的时间,用户下次请求这个文件的时候,在3.5天之内请求则直接走本地缓存获取,超过3.5天去请求当前文件,则会去请求服务器的资源,不再走缓存!

Last-Modified (文件最后修改时间)不变的前提下,随着时间的推移,该资源缓存的时间会越来越长~

相差较短时间

站在开发者的角度来解析这个问题,当我们自己在做测试启发式缓存的时候,容易出现错乱,就是感受不到启发式缓存的效果,不知道你们有没有遇到过。只要掌握上面的计算方法,一步步拆分,就可以轻松的识别和判断启发式缓存。

图片.png

再来看,还是刚才那个文件,在服务器修改了文件的内容,DateLast-Modified 只相差27秒,也就说当前文件只会缓存2.7秒。因为我们刚刚修改了服务器资源内容,需要强制刷新获取的最新文件,是发请求到服务器的,没有走本地缓存,所以这次是看不到效果的,正常是不能用强制刷新的;想要看到效果,在做测试的时候肯定会再次去修改服务器中该文件的内容,然后用普通刷新去看当前文件到底是不是走启发式缓存。

图片.png

当再次修改服务器资源后刷新页面,如上图所示,发现 config.js 还是请求的服务器资源!没有走缓存!如果走缓存的话,Size栏是disk cache 或者 memory cache,这是为什么呢?因为之前上次请求资源的DateLast-Modified决定下次请求是否走缓存,上次请求资源只缓存了2.7s,我们在服务器改了内容再返回页面去刷新查看结果的这个过程超过了2.7s就会重新请求服务器资源!

所以说,我们做测试的时候一定注意尽可能的把DateLast-Modified时间拉大一点,才能看出效果。

此时,我们把时间拉的稍微大一点,再去修改服务器中的资源,(49 - 33) * 0.1 大约会缓存一分半时间;

图片.png

在这一分半时间内,去服务器修改资源之后再去刷新页面,发现此时此刻 config.js 走的就是缓存了,我们服务器虽然修改了 config.js 里面的内容,但是在这个缓存的时间内仍然获取不到最新的内容!所以说系统的配置文件要配置协商缓存。

图片.png