强缓存、协商缓存,居然还有启发式缓存??

HTTP缓存属于客户端缓存,我们常认为浏览器有一个缓存数据库,用来保存一些静态文件,下面我们分为以下几个方面来简单介绍HTTP缓存

  • 缓存的规则
  • 缓存的方案
  • 缓存的优点
  • 不同刷新的请求执行过程

缓存的规则

缓存规则分为强制缓存协商缓存启发式缓存

强制缓存

当缓存数据库中有客户端需要的数据,浏览器如果判断本地缓存未过期,就直接使用,当缓存服务器没有需要的数据时,客户端才会向服务端请求。

协商缓存

又称对比缓存。浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。如果失效,服务端会返回新的数据

第一次访问

再次访问

通过两图的对比,我们可以很清楚的发现,在协商缓存生效时,状态码为304,并且报文大小和请求时间大大减少。

原因是,服务端在进行标识比较后,只返回header部分,通过状态码通知客户端使用缓存,不再需要将报文主体部分返回给客户端。

启发式缓存

启发式缓存就是无任何缓存相关的请求头的一种兜底策略,只有在服务端没有返回明确的缓存策略时才会激活浏览器的启发式缓存策略

如果响应中未显示Expires,Cache-Control:max-age或Cache-Control:s-maxage,并且响应中不包含其他有关缓存的限制,缓存可以使用启发式方法计算新鲜度寿命。通常会根据响应头中的2个时间字段 Date 减去 Last-Modified 值的 10% 作为缓存时间

sql 复制代码
sql
复制代码
// Date 减去 Last-Modified 值的 10% 作为缓存时间。
// Date:创建报文的日期时间, Last-Modified 服务器声明文档最后被修改时间
response_is_fresh =  max(0,(Date -  Last-Modified)) % 10

总结

  • 强制缓存如果生效,不需要再和服务器发生交互,而对比缓存不管是否生效,都需要与服务端发生交互。
  • 两类缓存规则可以同时存在,强制缓存优先级高于对比缓存,也就是说,当执行强制缓存的规则时,如果缓存生效,直接使用缓存,不再执行对比缓存规则。

缓存方案

强制缓存

浏览器是如何判断缓存数据是否失效呢

我们知道,在没有缓存数据的时候,浏览器向服务器请求数据时,服务器会将数据和缓存规则一并返回,缓存规则信息包含在响应header中。

对于强制缓存来说,响应header中会有两个字段来标明失效规则(Expires/Cache-Control)

使用chrome的开发者工具,可以很明显的看到对于强制缓存生效时,网络请求的情况

Expires

  • Expires的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据。
  • 不过Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。、
  • 另一个问题是,到期时间是由服务端生成的,但是客户端时间可能跟服务端时间有误差,这就会导致缓存命中的误差。所以HTTP 1.1 的版本,使用Cache-Control替代。

Cache-Control

  • Cache-Control 是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,默认为private。
  • private:客户端可以缓存
  • public:客户端和代理服务器都可缓存
  • max-age=xxx: 缓存的内容将在 xxx 秒后失效
  • no-cache:需要使用对比缓存来验证缓存数据(后面介绍)
  • no-store:所有内容都不会缓存,强制缓存,对比缓存都不会触发(对于前端开发来说,缓存越多越好,so...基本上和它说886)

举个例子

图中Cache-Control仅指定了max-age,所以默认为private,缓存时间为31536000秒(365天)。也就是说,在365天内再次请求这条数据,都会直接获取缓存数据库中的数据,直接使用。

协商缓存

对于协商缓存来说,缓存标识的传递是我们着重需要理解的,它在请求header和响应header间进行传递,一共分为两种标识传递,接下来,我们分开介绍。

Last-Modified / If-Modified-Since

Last-Modified:服务器在响应请求时,告诉浏览器资源的最后修改时间。

If-Modified-Since:

  • 再次请求服务器时,会在其请求头 上附带上 If-Modified-Since 字段(值就是第一次获取请求资源时响应头中返回的 Last-Modified 值)
  • 服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。
  • 若资源的最后修改时间大于If-Modified-Since,说明资源又被改动过,则响应整片资源内容,返回状态码200;
  • 若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。

Etag / If-None-Match(优先级高于Last-Modified / If-Modified-Since)

Etag:服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识hash值(生成规则由服务器决定)。

If-None-Match:

  • 再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。
  • 服务器收到请求后发现有头If-None-Match 则与被请求资源的唯一标识进行比对,
  • 不同,说明资源又被改动过,则响应整片资源内容,返回状态码200;
  • 相同,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。

last-modified/Etag区别

  • 时间粒度:

    • last-modified时间粒度为1秒。某些文件修改非常频繁,比如 1s 内修改了 N 次,这种修改无法判断
  • 资源消耗

    • etag需要生成hash值,消耗更大。last-modified是时间戳
  • etag优先级更高

启发式缓存

启发式缓存会引起什么问题吗??

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

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

总结

浏览器第一次请求:

浏览器再次请求:

缓存的优点

  • 减少了冗余的数据传递,节省宽带流量
  • 减少了服务器的负担,大大提高了网站性能
  • 加快了客户端加载网页的速度 这也正是HTTP缓存属于客户端缓存的原因。

不同刷新的请求执行过程

  • 浏览器地址栏中写入URL,回车:浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿。(最快)

  • F5:F5就是告诉浏览器,别偷懒,好歹去服务器看看这个文件是否有过期了。于是浏览器就战战兢兢的发送一个请求带上If-Modify-since。

  • Ctrl+F5:告诉浏览器,你先把你缓存中的这个文件给我删了,然后再去服务器请求个完整的资源文件下来。于是客户端就完成了强行更新的操作

作者:前端实习生鲸落

链接:juejin.cn/post/728084...

github地址:github.com/xiaojunnany...

个人博客:鲸落 (xiaojunnan.cn)

相关推荐
PAK向日葵3 分钟前
【算法导论】PDD 0817笔试题题解
算法·面试
加班是不可能的,除非双倍日工资2 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi3 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip3 小时前
vite和webpack打包结构控制
前端·javascript
excel3 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国4 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼4 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy4 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT4 小时前
promise & async await总结
前端
Jerry说前后端4 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化