当前位置: 首页 > news >正文

面试题:说说浏览器的缓存机制

面试题:说说浏览器的缓存机制

1 缓存过程简要分析

浏览器使用缓存中的数据将数据存入缓存中的大致流程为:

  • 浏览器每次发起请求时,首先在浏览器缓存中查找是否存在要请求的资源及其缓存标识(浏览器缓存资源时,通常会附带相应的缓存标识)。
  • 如果存在缓存资源及其缓存标识,则浏览器根据缓存控制策略(例如 Cache-Control 头信息)确定是否可以使用该缓存资源
  • 如果根据缓存控制策略不能使用缓存资源,浏览器会向服务器请求该资源。同时,如果服务器在响应中指示可以缓存该资源,则浏览器会将响应资源及其缓存标识存入浏览器缓存中

2 浏览器的缓存策略

浏览器通过强制缓存协商缓存这两种策略实现资源的缓存。

2.1 强制缓存

  • 解释:当浏览器向服务器发送请求时,服务器返回资源的同时,会使用 ExpiresCache-Control 响应头来控制是否缓存对应的资源。其中 Expires 的优先级 < Cache-Control 的优先级。通过上述这种方式实现的缓存就称之为强制缓存。

  • 使用场景:所谓强制缓存的使用,就是指,浏览器发送请求时,先在浏览器缓存中查找缓存数据及其标识,并根据缓存规则来决定是否使用该缓存数据的过程。强制缓存分为以下三种使用场景。

    场景描述图解
    不存在缓存数据及表示强制缓存失效,浏览器直接向服务器发起请求image-20240603235434460
    存在缓存结果及标识;但缓存结果已失效(由于过期等原因)强制缓存失效,浏览器使用协商缓存image-20240603235613430
    存在缓存结果及标识;且缓存结果未失效浏览器直接返回缓存结果image-20240603235731516
  • Expires 响应头:该响应头在 HTTP/1.0 中用于控制缓存。

    • 取值:对应资源缓存的到期时间。每次浏览器发送请求时,如果在浏览器缓存中找到了对应的缓存资源,则需要将客户端时间和过期时间进行对比。如果客户端时间 < 过期时间,则直接使用缓存结果,否则直接向服务器发送 HTTP 请求,获取对应的资源。

      Expires: Mon, 16 Apr 2018 01:41:50 GMT
      
    • 缺点:该响应头被废弃的原因在于,Expires 控制缓存的原理为将客户端的时间与服务端的时间做对比,一旦二者时间不同步,此时缓存资源的过期时间将不再有意义。因为在 Cache-Control 中,将绝对的时间修改为相对的时间,避免客户端和服务端时间不同步带来的问题。

  • Cache-control 响应头:该响应头在 HTTP/1.1(当前常用) 中用于控制缓存。

    • 取值

      取值含义
      public所有内容都被缓存;客户端和代理服务器都可以缓存
      private默认值:所有内容都被缓存;只有客户端才能缓存
      no-cache所有内容都被缓存;只有客户端才能缓存;是否使用缓存需要经过协商缓存来决定
      no-store所有内容都不会被缓存
      max-age=xxx所有缓存的内容将在 xxx 秒后失效
  • 对比:强制缓存的两种实现

    区别ExpiresCache-Control
    时间值绝对值相对值
    优先级

    如果同时使用 ExpiresCache-Control 实现强制缓存,则只有 Cache-Control 生效。

2.2 协商缓存

  • 解释:当浏览器请求强制缓存中的缓存数据时,如果存在缓存数据及其标识,但缓存结果失效,此时浏览器无法确定该缓存数据是否仍然有效。在这种情况下,浏览器会携带对应的资源标识发送 HTTP 请求,以确认缓存的数据是否与服务器上的数据一致。如果数据一致,服务器会返回 304 状态码,告诉浏览器可以继续使用缓存中的数据;如果数据不一致,服务器会返回 200 状态码,并提供最新的数据。通过这种方式访问缓存中的数据的方式称之为协商缓存。

  • 使用场景:所谓协商缓存的使用,指的是当浏览器在缓存中找到失效的缓存数据后,通过向服务器发送请求来确认缓存数据是否仍然有效的一种缓存机制。协商缓存分为以下两种适用场景。

    场景描述图解
    协商缓存生效服务端返回 304 响应,通知客户端可以使用缓存中的对应数据image-20240604000748403
    协商缓存失效服务端返回 200 响应,返回给客户端最新的数据
  • Last-Modified 响应头和 If-Modified-Since 请求头:用于控制协商缓存。

    • 响应头 Last-Modified:服务器在响应请求时,通过该响应头返回资源文件在服务器中最后被修改的时间
    • 请求头 If-Modified-Since:客户端在发送请求时,携带此请求头,其内容为上次响应中返回的 Last-Modified 值,用于告诉服务器对应资源上次请求返回的最后修改时间。服务器收到请求后,会将 If-Modified-Since 的值与资源在服务器中最后的修改时间进行对比。如果服务器上的资源最后修改时间晚于该请求头的值,则重新返回资源,状态码为 200;否则返回 304,表示缓存资源没有更新,可以继续使用缓存文件。
  • Etag 响应头和 If-None-Match 请求头:用于控制协商缓存。

    • 响应头 Etag:服务器在响应请求时,通过该响应头返回资源文件的唯一标识
    • 请求头 If-None-Match:客户端在发送请求时,携带此请求头,其内容为上次响应中返回的 Etag 值,用于告诉服务器对应资源上次请求返回的唯一标识值。服务器收到请求后,会将 If-None-Match 的值与资源在服务器中的 Etag 进行对比。不一致则重新返回资源,状态码为 200;一致则返回 304,表示缓存资源没有更新,可以继续使用缓存文件。
  • 对比:协商缓存的两种实现

    • Etag/If-Not-Match 优先级高于 Last-Modified/If-Modified-Since,同时存在则只有 Etag/If-Not-Match 生效。

3 浏览器缓存的存放位置

  • 存放位置:浏览器可以将其缓存存放在内存中(memory cache),也可以存放在硬盘中(disk cache)

  • 缓存分类:根据缓存的存放位置,可以将缓存分为内存缓存硬盘缓存

    一般来说,浏览器会根据资源的大小、使用频率等因素,将 JS、图片和 CSS 等资源存放在内存缓存或硬盘缓存中。频繁访问的小型资源通常存放在内存缓存中,而较大的资源则可能存放在硬盘缓存中。每次刷新页面时,浏览器会优先从内存缓存中读取资源,如果没有找到,则会从硬盘缓存中读取。

  • 缓存的读取顺序内存缓存 => 硬盘缓存

    举例理解:当我们首次访问一个 URL 时,浏览器会缓存响应中允许缓存的数据。关闭浏览器后,对应的缓存数据会被写入到硬盘中。下一次打开浏览器,加载对应网页时,浏览器会首先从硬盘缓存中读取缓存数据。如果此时刷新网页,浏览器则会从内存中读取缓存数据。

4 第一次 HTTP 请求对于浏览器缓存的意义

当浏览器第一次请求资源时,服务器通常会在响应中返回一些与缓存相关的头部字段,这些字段用于指导浏览器如何缓存该资源。这些头部字段包括但不限于 Last-ModifiedExpiresCache-ControlETag

HTTP/1.1 200 OK
Date: Mon, 03 Jun 2024 10:00:00 GMT
Last-Modified: Mon, 01 Jun 2024 10:00:00 GMT
Expires: Mon, 10 Jun 2024 10:00:00 GMT
Cache-Control: max-age=604800
ETag: "abc123"
Content-Type: text/html
Content-Length: 1234

5 总结:浏览器的缓存机制

  • 强制缓存优先于协商缓存。强制缓存生效则直接使用缓存数据,否则进行协商缓存。
  • 协商缓存由服务器决定是否使用缓存中的数据。协商缓存生效则服务器返回 304,使用缓存数据,否则重新请求结果,再存入浏览器缓存中。
image-20240604003331630

REFERENCES

https://juejin.cn/post/6844903593275817998

相关文章:

  • WebSocket 断网重连、心跳检测功能封装
  • 极简网络用户手册(1)
  • 【代码随想录算法训练营第37期 第二十八天 | LeetCode93.复原IP地址、78.子集、90.子集II】
  • 算法简单笔记3
  • C语言:(动态内存管理)
  • 攻防世界maze做法(迷宫题)
  • appium元素定位工具_uiautomatorviewer.bat
  • WiFi模块ESP32手机远程控制方法
  • docker学习--最详细的docker run 各子命令解释与应用
  • C# :IQueryable IEnumerable
  • Prism 入门04,导航功能
  • 【STL源码剖析】deque 的使用
  • Docker 私有仓库部署和管理
  • 构建一个java项目,对于安全方面,需要哪些业务模块
  • axios学习
  • JavaScript 如何正确处理 Unicode 编码问题!
  • [译]Python中的类属性与实例属性的区别
  • ES6 学习笔记(一)let,const和解构赋值
  • JavaScript 一些 DOM 的知识点
  • Javascript基础之Array数组API
  • Java多态
  • Laravel Telescope:优雅的应用调试工具
  • Meteor的表单提交:Form
  • mysql 数据库四种事务隔离级别
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • Sublime text 3 3103 注册码
  • windows下如何用phpstorm同步测试服务器
  • 从零开始在ubuntu上搭建node开发环境
  • 前端面试之闭包
  • 小程序滚动组件,左边导航栏与右边内容联动效果实现
  • 移动端高清、多屏适配方案
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • ‌[AI问答] Auto-sklearn‌ 与 scikit-learn 区别
  • #### go map 底层结构 ####
  • (20050108)又读《平凡的世界》
  • (39)STM32——FLASH闪存
  • (C++17) std算法之执行策略 execution
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (十三)Flink SQL
  • (算法)Game
  • (转)Oracle 9i 数据库设计指引全集(1)
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • (转载)CentOS查看系统信息|CentOS查看命令
  • (自用)gtest单元测试
  • .env.development、.env.production、.env.staging
  • .NET Core 项目指定SDK版本
  • .NET Core 中的路径问题
  • .Net Core 中间件与过滤器