浏览器http缓存机制

news2025/1/12 23:09:57

1、前言

前端缓存主要是分为HTTP缓存浏览器缓存。其中HTTP缓存是在HTTP请求传输时用到的缓存,主要在服务器代码上设置;而浏览器缓存则主要由前端开发在前端js上进行设置。
在这里插入图片描述
http缓存是web缓存的核心,是最难懂的那一部分,也是最重要的那一部分。

2、HTTP缓存位置

从缓存位置上来说分为四种,并且各自有优先级,当依次查找缓存且都没有命中的时候,才会去请求网络。

  • Service Worker
  1. 行在浏览器背后的独立线程,一般可以用来实现缓存功能
  2. 因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS
    协议来保障安全
  3. Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
  • Memory Cache
  1. 内存中的缓存,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片等。
  2. 读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。
  3. 一旦我们关闭 Tab 页面,内存中的缓存也就被释放了
  4. 访问过页面以后,再次刷新页面,可以发现很多数据都来自于内存缓存
  • Disk Cache
  1. Disk Cache 也就是存储在硬盘中的缓存,读取速度慢点
  2. Disk Cache 比Memory Cache胜在容量和存储时效性上
  3. 在所有浏览器缓存中,Disk Cache 覆盖面基本是最大的
  4. 它会根据 HTTP Herder 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求
  • Push Cache
  1. Push Cache是推送缓存,是 HTTP/2 中的内容
  2. 只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂
  3. 在Chrome浏览器中只有5分钟左右,同时它也并非严格执行HTTP头中的缓存指令。

如果以上四种缓存都没有命中的话,那么只能发起请求来获取资源了。

那么为了性能上的考虑,大部分的接口都应该选择好缓存策略,通常浏览器缓存策略分为两种:强缓存和协商缓存,并且缓存策略都是通过设置 HTTP Header 来实现的。

3、HTTP缓存-强缓存

对于强制缓存而言,如果浏览器判断所请求的目标资源有效命中,则直接从强制缓存中返回请求响应,无须与服务器进行任何通信。返回200的状态码。

在浏览器控制台NetWork中的体现为:
200 OK (from disk cache) 或者 200 OK (from memory cache)

  • 200 OK (from disk cache) HTTP状态码200,缓存的文件从硬盘中读取
  • 200 OK (from memory cache) HTTP状态码200,缓存的文件从内存中读取

强缓存可以通过设置两种 HTTP Header 实现:Expires 和 Cache-Control。

3.1基于expires实现
request header: Last-modified
response header: expires

缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。需要和Last-modified结合使用。Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。

  • HTTP1.0协议中声明的用来控制缓存失效日期时间戳的字段
  • 由服务器端指定后通过响应头告知浏览器,浏览器在接收到带有该字段的响应体后进行缓存。
  • 如果浏览器再次发起相同的资源请求,便会对比expires与本地当前的时间戳。
    • 当前请求的本地时间戳小于expires的值,则说明浏览器缓存的响应还未过期,无须向服务器端再次发起请求
    • 当本地时间戳大于expires值,缓存过期,重新向服务器发起请求。(仅过期才能允许再次发送请求)
  • expires判断的局限性
    • 对本地时间戳过分依赖
    • 如果客户端本地的时间与服务器端的时间不同步,或者对客户端的时间进行主动修改,那么对于缓存过期的判断可能就无法和预期相符
  • 解决expires判断的局限性:HTTP1.1协议开始新增了cache-control字段

3.2基于cache-control实现
在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存。比如当Cache-Control:max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。

Cache-Control:max-age=N,N就是需要缓存的秒数。从第一次请求资源的时候开始,往后N秒内,资源若再次请求,则直接从磁盘(或内存中读取),不与服务器做任何交互。

Cache-control中因为max-age后面的值是一个滑动时间,从服务器第一次返回该资源时开始倒计时。所以也就不需要比对客户端和服务端的时间,解决了Expires所存在的巨大漏洞。

基于cache-control实现的强缓存是当下项目中的常规方法,而基于expires实现的强缓存不被推荐使用。

Cache-Control 可以在请求头或者响应头中设置,并且可以组合使用多种指令

  1. max-age:(单位为s)表示响应资源能被缓存多久
    • max-age和expires同时存在,则以max-age为准
  2. s-maxage:(单位为s)缓存在代理服务器中的过期时长(仅当设置了public属性值时才是有效的)
    • max-age和s-maxage并不互斥。他们可以一起使用
  3. no-cache:强制进行协商缓存
    • Cache-control中设置了no-cache,那么该资源会直接跳过强缓存的校验,直接去服务器进行协商缓存
  4. no-store:禁止使用任何缓存
    • 客户端的每次请求都需要服务器端给予全新的响应
    • no-cache与no-store是两个互斥的属性值,不能同时设置
  5. public:表示响应资源既可以被浏览器缓存,又可以被代理服务器缓存
  6. private:限制了响应资源只能被浏览器缓存
    • public和private就是决定资源是否可以在代理服务器进行缓存的属性
    • 如果这两个属性值都没有被设置,则默认为private
    • public和private 也是一组互斥属性

Cache-control如何设置多个值呢?用逗号分割

Cache-control:max-age=10000,s-maxage=200000,public

如果要考虑向下兼容的话,在Cache-control不支持的时候,还是要使用Expires,这也是我们当前使用的这个属性的唯一理由。

3.3强缓存两种方式的区别

  • Expires 是 HTTP/1 的产物,受限于本地时间,如果修改了本地时间,可能会造成缓存失效
  • Expires 是http1.0的产物,Cache-Control是http1.1的产物
  • expires/cache-control两者同时存在的话,Cache-Control优先级高于Expires
  • 在某些不支持HTTP1.1的环境下,Expires就会发挥用处
  • Expires其实是过时的产物,现阶段它的存在只是一种兼容性的写法

3.4强缓存的缺陷
强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容,那我们如何获知服务器端内容是否已经发生了更新呢?此时我们需要用到协商缓存策略。

4、HTTP缓存-协商缓存

顾名思义,协商缓存就是在使用本地缓存之前,需要向服务器发起一次GET请求,与之协商当前浏览器保存的本地缓存是否已经过期。通常是采用所请求资源的最近一次的修改时间戳来判断的。

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:

  • 协商缓存生效(文件未更新),返回304和Not Modified。

  • 协商缓存失效(文件更新),返回200和请求结果。

协商缓存可以通过设置两种 HTTP Header 实现:Last-Modified 和 ETag 。

4.1基于last-modified实现

  1. 首先需要在服务器端读出文件修改时间
  2. 将读出来的修改时间赋给响应头的last-modified字段
  3. 最后设置Cache-control:no-cache

第一次请求,服务端代码

 const data = fs.readFileSync('./imgs/CSS.png');//读取资源
 // 1.读取修改的时间
 const { mtime } = fs.statSync('./imgs/CSS.png');
 // 2.设置文件最后修改时间
 res.setHeader('last-modified',mtime.toUTCString())
 // 3.强制设置为协商缓存
 res.setHeader('Cache-Control','no-cache');
 res.end(data);

第二次及以后的每一次请求,服务器端代码

 const data = fs.readFileSync('./imgs/CSS.png');//读取资源
 const { mtime } = fs.statSync('./imgs/CSS.png');//读取修改的时间
 const ifModifiedSince = req.headers['if-modified-since'];//读取请求头携带的时间(第一次返回给客户端的文件修改时间)
 if (ifModifiedSince === mtime.toUTCString()) {
     // 如果两个时间一致,则文件没被修改过,返回304
 	res.statusCode = 304;
 	res.end();//因为缓存生效,不需要返回数据
 	return;// 避免返回新的last-modified
 }
 res.setHeader('last-modified',mtime.toUTCString())// 设置文件最后修改时间
 res.setHeader('Cache-Control','no-cache');// 强制设置为协商缓存
 res.end(data);

流程

  • 客户端第一次请求目标资源的时,服务器返回的响应标头包含last-modified字段,值是该资源的最后一次修改的时间戳,以及cache-control:no-cache
  • 当客户端再次请求该资源的时候,会携带一个if-modified-since字段,其值正是上次响应头中last-modified的字段值
  • 如果客户端请求头携带的if-modified-since字段对应的时间与目标资源的时间戳进行对比,如果没有变化则返回一个304状态码。
  • 如果有变化则返回最新的last-modified标头和Cache-Control:no-cache

last-modified的不足

  • last-modified是根据请求资源的最后修改时间戳进行判断的,虽然请求的文件资源进行了编辑,但是内容并没有发生任何变化,时间戳也会更新,从而导致协商缓存时关于有效性的判断验证为失效,需要重新进行完整的资源请求。浪费了网络的带看资源,延长获取资源的时间
  • 标识文件资源修改的时间戳单位是秒,如果文件修改的速度非常快,假设在几百毫秒内完成,那么通过时间戳的方式来验证缓存的有效性,是无法识别出该次文件资源的更新的。

综合,以上两种不足可知,基于last-modified实现的协商缓存,服务器无法根据资源修改的时间戳识别出真正的更新,进而导致重新发起了请求

4.2基于Etag实现
为了弥补通过时间戳判断的不足,从HTTP1.1规范开始新增了一个Etag的头信息,即实体标签。 其内容主要是服务器为不同的资源进行哈希计算所生成的一个字符串,该字符串类似于文件指纹,只要文件内容编码存在差异,对应的Etag对文件资源进行更精准的变化感知。

也就是说,ETag就是将原先基于last-modified协商缓存的比较时间戳的形式修改成了比较文件指纹。

文件指纹:根据文件内容计算出的唯一哈希值。文件内容一旦改变则指纹改变。

服务端代码:
在这里插入图片描述
流程

  • 第一次请求资源时,服务端将要返回给客户端的数据通过ETag模块进行哈希计算生成一个字符串,这个字符串类似于文件指纹。
  • 第一次请求资源时,服务端将要返回给客户端的数据通过ETag模块进行哈希计算生成一个字符串,这个字符串类似于文件指纹。
  • 检测客户端的请求标头中的if-None-Match字段的值和第一步计算的值是否一致,一致则返回304。
  • 如果不一致则返回etag标头和Cache-Control:no-cache

etag的不足

在协商缓存中,Etag并非last-modified的替代方案而是一种补充方案,因为依旧存在一些弊端。

  • 服务器对于生成文件资源的Etag需要付出额外的计算开销,如果资源的尺寸比较大,数量较多且修改频繁,那么生成的Etag的过程就会影响服务器的性能。
  • Etag字段值的生成分为强验证和弱验证,强验证根据资源内容进行生成,能够保证每个字节都相同,弱验证则根据资源的部分属性来生成,生成速度快但无法确保每个字节都相同,并且在服务器集群场景下,也会因为准确不够而降低协商缓存有效性的成功率,所以恰当的方式是根据具体的资源使用场景选择恰当的缓存校验方式。

4.3Etag/last-modified对比

  • 首先在精确度上,Etag要优于Last-Modified。
    Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;如果是负载均衡的服务器,各个服务器生成的Last-Modified也有可能不一致。
  • 第二在性能上,Etag要逊于Last-Modified
    Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。
  • 第三在优先级上,服务器校验优先考虑Etag

5、怎么设置缓存

  • 普遍服务器默认开启强缓存
  • 缓存是缓存在前端,但实际的代码是后端同学写的,如果需要实现前端缓存的话,通知后端的同学加响应头就好了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/117913.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【大数据clickhouse】clickhouse 数据备份与恢复

一、前言 与其他的数据存储引擎类似,clickhouse承载着大数据量级的数据存储,对于数据的备份与恢复也是必须考虑的,本文将通过操作演示下如何对clickhouse数据进行备份与恢复。 官网说明:官网备份操作说明clickhouse可以通过手动进…

NEMU(RISC-V64)基础知识(一)

目录 1、术语和定义 2、CISC和RISC的区别 3、vimtutor指令查看常见VIM使用命令 4、GDB调试 5、x86中寄存器 6、x86中指令的具体行为 7、中断和异常 8、RISC-V的中断 9、一条指令在NEMU中的执行过程 10、NEMU中的输入输出 11、在NEMU的运行时环境中执行程序步骤 12、…

HarmonyOS使用ArkUI绘制圣诞树

一、前言 起因我参加了 “挑战代码画颗圣诞树” 活动,又因为本次推出一个“圣诞定制勋章”活动,一个是传资源,一个是写文章,为了更好的把知识传递给大家,所以我又出了这篇文章,大家进来一起学习一下吧。 二…

Linux- 系统随你玩之--操作文件和目录

文章目录1、前言2、文件、目录相关的指令2.1、当前所在目录2.2、当前目录所有的文件和目录2.3、切换当前工作目录2.4、 创建目录与文件2.6 、拷贝文件3 、文本查看3.1、cat 查看文件内容3.2、head 查看前n行内容3.3、tail 查询后n行内容4、文本编辑4.1、vi 指令4.2、more 指令4…

华为三层交换机做中继,WinServer2012当DHCP服务器

ENSP桥接一台 Windows Server&#xff0c;当DHCP服务器 1、拓扑图 2、汇聚交换机设置 <Huawei>sys# 关闭消息提示 [Huawei]undo in en[Huawei]sys SW1# 批量创建 VLAN [SW1]vlan batch 10 20 30 100# 设置 VLAN 为 Trunk [SW1]int g0/0/1 [SW1-GigabitEthernet0/0/1]p…

【电商】电商后台---FMS财务管理系统

文章对电商财务系统进行了系统的介绍&#xff0c;希望通过此文能够加深你对电商系统的认识。 目前互联网电商公司的系统非常多、系统间的关系也非常复杂&#xff0c;最近各公司都热衷于中台&#xff0c;应用的技术也相当之多&#xff0c;技术实力弱点的公司只能借助于各平台加快…

uAvionix获得FAA合同,部署和演示多个无人机同时飞行的C波段频率分配管理(FAM)

uAvionix宣布&#xff0c;它已赢得美国联邦航空管理局(FAA)的合同&#xff0c;作为uAvionix SkyLine™指挥和控制通信服务提供商(C2CSP)管理平台的组件&#xff0c;对频率分配管理器(FAM)进行多次端到端演示。 这次大规模演示将使运营SkyLine平台的频率管理组织(FMO)能够将国际…

基于STM32与TB6600的机械臂项目(代码开源)

前言&#xff1a;本文为手把手教学STM32的机械臂项目——Robot Arm&#xff0c;本次项目采用的是STM32作为MCU。该机械臂的基础模型为国外开源项目&#xff0c;诸多前辈经过长时间的验证与改进&#xff0c;其机械臂精度可以满足日常需求。本项目机械臂为三自由度机械臂&#xf…

mongodb-9.数据库连接,集合创建

文章目录数据库连接集合创建查询删除查询显示指定字段限制查询条数 limit &#xff0c;skip排序索引创建聚合查询数据库连接 mongodb URL mongodb://[username:password]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]语法说明如下&#xff1a;…

JSP ssh网络点餐系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 JSP ssh网络点餐系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式 开发。开发环境为TOMCAT7.0,Mye…

vue3 antd项目实战——input输入框限制输入内容和长度,Form表单动态校验规则

input输入框设置只能输入中文&#xff0c;输入长度为20&#xff0c;输入不能为空知识调用场景复现解决方案1.下方有提示文字2.限制输入内容只能是中文3.限制输入长度为204.动态校验规则&#xff08;必填项&#xff09;input源代码&#xff08;按需调整即可&#xff09;知识调用…

【区块链 | EVM】深入理解学习EVM - 深入理解EVM操作码,让你写出更好的智能合约

那些非典型的开销导致经典的软件设计模式在合约编程语言中看起来既低效又奇怪。如果想要识别这些模式并理解他们导致效率变高/低的原因&#xff0c;你必须首先对以太坊虚拟机&#xff08;即 EVM&#xff09;有一个基本的了解。 你的一些编程“好习惯”反而会让你写出低效的智能…

Linux当中的Sersync实时同步服务及其实战举例

目录 一、实时同步 1.定义 2.原理 3.实时同步场景 4.实时同步工具 &#xff08;1&#xff09;sersync &#xff08;2&#xff09;Lysncd 二、实时同步实例 1.环境规划 2.配置思路 NFS存储服务如下&#xff1a; &#xff08;1&#xff09;安装NFS &#xff08;2&am…

40. 使用块的网络(VGG)

虽然AlexNet证明深层神经网络卓有成效&#xff0c;但它没有提供一个通用的模板来指导后续的研究人员设计新的网络。 在下面的几个章节中&#xff0c;我们将介绍一些常用于设计深层神经网络的启发式概念。 与芯片设计中工程师从放置晶体管到逻辑元件再到逻辑块的过程类似&#x…

Node.js--》三大常见模块的使用讲解

目录 fs文件系统模块 fs.readFile()方法 fs.writeFile()方法 readFile与writeFile的使用 fs模块路径动态拼接问题 path路径模块 path.join()方法 path.basename() path.extname() path.parse() http模块 req请求对象 res响应对象 解决中文乱码问题 响应不同内容…

Python实现猎人猎物优化算法(HPO)优化支持向量机回归模型(SVR算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 猎人猎物优化搜索算法(Hunter–prey optimizer, HPO)是由Naruei& Keynia于2022年提出的一种最新的优…

计算机系统基础实验 - 同符号浮点数加法运算/无符号定点数乘法运算的机器级表示

实验3 同符号浮点数加法运算/无符号定点数乘法运算的机器级表示 实验序号&#xff1a;3 实验名称&#xff1a;同符号浮点数加法运算/无符号定点数乘法运算的机器级表示 适用专业&#xff1a;软件工程 学 时 数&#xff1a;2学时 一、实验目的 1.掌握定点数乘法溢出的判定方法…

Kafka触发Rebalance的场景分析

文章目录前言触发Rebalance的原因1. 消费者成员发生变化2. 分区数发生变化3. 订阅Topic发生变化Rebalance全流程介绍场景一&#xff1a;新成员入组场景二&#xff1a;成员主动离组场景三&#xff1a;成员崩溃离组场景四&#xff1a;组成员提交位移前言 所谓Rebalance就是让Con…

Python小工具-复制嵌套目录下的多个word文档到指定目录

文章目录Python小工具-复制嵌套目录下的多个word文档到指定目录需求原始数据工具实现思路代码实现1-6 配置项目7 定义file_type_to_reduce_dir函数完成文件复制或移动8 定义list_dir_by_level函数完成遍历调用函数并执行待改进地方完整代码自我反省Python小工具-复制嵌套目录下…

全志 Linux 系统启动优化 启动优化速度方式 优化启动流程 优化uboot 优化kernel等

文章目录1 概述2 启动速度优化简介2.1 启动流程2.2 测量方法2.2.1 printk time2.2.2 initcall_debug2.2.3 bootgraph.2.2.4 bootchart2.2.5 gpio 示波器.2.2.6 grabserial.2.3 优化方法2.3.1 boot0启动优化2.3.1.1 非安全启动.2.3.1.2 安全启动2.3.2 uboot启动优化2.3.2.1 完全…