深入理解浏览器的缓存机制之协商缓存与强缓存

news2024/11/15 22:45:01

目录

什么是浏览器缓存

浏览器缓存的分类

🎗️ 强缓存

🎗️ 协商缓存

👉🏻 缓存请求流程

👉🏻 为什么要有Etag

👉🏻 缓存优先级

👉🏻 启发式缓存

👉🏻 其他补充

👉🏻 注意场景

用户行为对缓存的影响


什么是浏览器缓存


缓存是指代理服务器或客户端本地磁盘内保存的资源副本,利用缓存可减少对源服务器的访问,节省通信流量和通信时间。

浏览器缓存(Brower Caching)指的就是浏览器在本地磁盘对用户最近请求过的文档(文件)进行存储(缓存),以便在下一次访问时重复使用,即当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档,从而节省带宽、提升访问速度、降低服务器压力。

本文所说的HTTP缓存机制就是利用HTTP响应头将所请求的资源在浏览器中进行缓存。

当我们在浏览器中打开一个页面时,浏览器会根据你输入的URL到对应的服务器上请求你想要的数据资源。但这个过程中可能页面可能需要等待一段时间(白屏时间)才能渲染到你的页面中。

浏览器缓存的优点有:

1. 减少了冗余的数据(重复资源)传输,节省了网费

2. 减少了服务器的负担(开销),大大提升了网站的性能

3. 加快了(提高)客户端加载网页的速度

在前端开发面试中,浏览器缓存是web性能优化面试题中很重要的一个知识点,从而说明浏览器缓存是提升web性能的一大利器,但是浏览器缓存如果使用不当,也会产生很多问题,正所谓是,想说爱你,并不是很容易的事。

所以,结合最近遇到的案例,本文对浏览器缓存相关的知识进行总结归纳,希望对大家有所帮助。

浏览器缓存的分类


浏览器缓存方式主要有两类:缓存协商(对比缓存)和彻底缓存,也有称之为协商缓存强缓存。 浏览器在第一次请求发生后,再次请求时:

1. 浏览器会先获取该资源缓存的header信息,根据其中的expirescahe-control判断是否命中强缓存,若命中则直接从缓存中获取资源,包括缓存的header信息,本次请求不会与服务器进行通信;

2. 如果没有命中强缓存,浏览器会发送请求到服务器,该请求会携带第一次请求返回的有关缓存的header字段信息(Last-Modified / IF-Modified-SinceEtag / IF-None-Match),由服务器根据请求中的相关header信息来对比结果是否命中协商缓存,若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取;否则返回最新的资源内容

🎗️ 强缓存

强缓存指的是在缓存时间内不会向服务器发起请求,只有过期之后才会向服务器发起请求,整个流程如下所示:

在浏览器中,强缓存分为Expires(http1.0规范)、cache-control(http1.1规范)两种。

强缓存是利用http的返回头(响应头)中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间。

 Expires

Expires 该字段是http1.0时的规范,用于表示资源的过期时间的请求头字段,它的值为一个绝对时间的GMT格式的时间字符串,是由服务器端返回的。比如,Expires:Mon,18 Oct 2066 23:59:59 GMT。这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以,当服务器与客户端时间偏差较大时,就会导致缓存混乱。

在浏览器第一次请求资源时,服务器端的响应头会附上Expires这个响应字段,当浏览器在下一次请求这个资源时会根据上次的Expires字段是否使用缓存资源(当请求时间小于服务端返回的到期时间,直接使用缓存数据)

expires是根据本地时间来判断的,假设客户端和服务器时间不同,会导致缓存命中误差

  Cache-Control

我们已经知道了,上面我们提到的Expires有个缺点,当客户端本地时间被修改时浏览器会直接向服务器请求新的资源,为了解决这个问题,在http1.1规范中,提出了cache-control字段,且这个字段优先级高于上面提到的Expires,值是相对时间。

Cache-Control是http1.1时出现的header信息,主要是利用该字段的max-age值来进行判断,它是一个相对时间,例如,Cache-Control:max-age=3600,代表着资源的有效期是3600秒。

cache-control除了该字段外,还有下面几个比较常用的设置值:

1. no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。

2. no-store:直接禁止浏览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。

3. public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。

4. private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。

Cache-Control与Expires可以在服务端配置同时启用,同时启用的时候Cache-Control优先级高。

 总结一下 cache-control 常见的属性值:

属性值备注
max-age3600例如,值为3600,表示(当前时间+3600秒)内不与服务器请求新的数据资源
s-maxage和max-age一样,但这个是设定代理服务器的缓存时间
private内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存)
public所有内容都将被缓存(客户端和代理服务器都可缓存)
no-store不缓存任何数据
no-cache储存在本地缓存区中,只是在与原始服务器进行新鲜度再验证之前,缓存不能将其提供给客户端使用

🎗️ 协商缓存

协商缓存都会向服务器发送请求,判断缓存数据是否过期,过期的话会返回新的内容,没有过期则使用本地的缓存数据。对于协商缓存主要利用两个字段:Last-Modify、Etag。

上面提到的强缓存都是由本地浏览器在确定是否使用缓存,当浏览器没有命中强缓存时就会向浏览器发送请求,验证协商缓存是否命中,如果缓存命中则返回304状态码,否则返回新的资源数据。

协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问,这主要涉及到下面两组header字段,这两组搭档都是成对出现的,即浏览器第一次发出请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。

Last-Modify/If-Modify-Since 浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。 当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。 如果命中缓存,则返回304,并且不会返回资源内容,并且不会返回Last-Modify。

ETag/If-None-Match 与Last-Modify/If-Modify-Since不同的是,Etag/If-None-Match返回的是一个校验码。ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化。服务器根据浏览器上送的If-None-Match值来判断是否命中缓存。 与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化。

🧤 小结:协商缓存是由服务器来确定资源是否可用,这将涉及到两组字段成对出现的,在浏览器第一次发出请求时会带上字段(Last-Modified或者Etag),则后续请求则会带上对于的请求字段(if-modified-since或者if-none-Match),若响应头没有Last-Modified或者Etag,则请求头也不会有对应的字段。

  • Last-modified表示本地文件最后修改时间,由服务器返回
  • if-modified-since浏览器在请求数据时返回的,值是上次浏览器返回的Last-modified
  • ETag是一个文件的唯一标识符,当资源发生变化时这个ETag就会发生变化。弥补了上面last-modified可能出现文件内容没有变化但是last-modified发生了变化出现重新向服务器请求资源情况。这个值也是又服务器返回的
  • if-none-match是浏览器请求数据时带上的字段,值是上次服务器返回的ETag

如果你觉得还是有点云里雾里,可以参看以下请求流程图,相信可以很快明白何为协商缓存

👉🏻 缓存请求流程

我们结合强缓存,来捋一下浏览器缓存具体的请求流程

1. 当浏览器发起一个资源请求时,浏览器会先判断本地是否有缓存记录,如果没有会向浏览器请求新的资源,并记录服务器返回的last-modified

2. 如果有缓存记录,先判断强缓存是否存在(cache-control优先于expires,后面会说),如果强缓存的时间没有过期则返回本地缓存资源(状态码为200)

3. 如果强缓存失效了,客户端会发起请求进行协商缓存策略,首先服务器判断Etag标识符,如果客户端传来标识符和当前服务器上的标识符是一致的,则返回状态码 304 not modified(不会返回资源内容)

4. 如果没有Etag字段,服务器会对比客户端传过来的if-modified-match,如果这两个值是一致的,此时响应头不会带有last-modified字段(因为资源没有变化,last-modified的值也不会有变化)。客户端304状态码之后读取本地缓存。如果last-modified

5. 如果Etag和服务器端上的不一致,重新获取新的资源,并进行协商缓存返回数据。

👉🏻 为什么要有Etag

你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难以解决的问题:

1. 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET。

也就是说,在没有修改文件内容情况下文件的最后修改时间可能也会改变,这会导致客户端认为这文件被改动了,从而重新请求;

2. 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)。使用 Etag 就能够保证这种需求下客户端在 1 秒内能刷新多次。

3. 某些服务器不能精确的得到(获取)文件的最后修改时间。

Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。 强缓存与协商缓存的区别可以用下表来表示:

缓存类型获取资源形式状态码发送请求到服务器
强缓存从缓存取200(from cache否,直接从缓存取
协商缓存从缓存取304(Not Modified)否,通过服务器来告知缓存是否可用

 状态码区别

  • 200 请求成功,服务器返回全新的数据
  • 200 from memory cache / from disk cache 本地强缓存还在有效期,直接使用本地缓存
  • 304 请求成功,走了协商缓存,服务器判定(EtagLast-modified)没有过期,告知浏览器使用缓存 

from memory cache 是页面刷新的时候内存取的。from disk cache 页面标签关闭后从磁盘取的

👉🏻 缓存优先级

expirescache-control如果同时存在时,cache-control会覆盖expiresexpires无效,无论是否过期,即 Cache-control > expires

强缓存和协商缓存如果同时存在时,会去先对比强缓存是否还再有效期,如果强缓存生效则对比协商缓存,即强缓存 > 协商缓存

协商缓存Etaglast-modified同时存在时,会先比较Etaglast-modified无效,即Etag > last-modified

 扩展补充:

在http1.0规范时还有一个Pragma缓存策略,那时候Cache-control(http1.1)还没出来,它与 Cache-Control: no-cache 效果一致。强制要求缓存服务器在返回缓存的版本之前将请求提交到源头服务器进行验证。

◾ 关于Pragma:

Pragma
 是一个在 HTTP/1.0 中规定的通用首部,这个首部的效果依赖于不同的实现,所以在“请求 - 响应”链中可能会有不同的效果。它用来向后兼容只支持 HTTP/1.0 协议的缓存服务器,那时候 HTTP/1.1 协议中的 Cache-Control 还没有出来。

备注: 由于 Pragma 在 HTTP 响应中的行为没有确切规范,所以不能可靠替代 HTTP/1.1 中通用首部 Cache-Control,尽管在请求中,假如 Cache-Control 不存在的话,它的行为与 Cache-Control: no-cache 一致。建议只在需要兼容 HTTP/1.0 客户端的场合下应用 Pragma 首部。

paragma -> Cache-control -> expires -> Etag -> last-modified 

👉🏻 启发式缓存

这个会缓存策略是浏览器默认的,如果发送一个网络请求没有expirescache-control,但是又有last-modified字段,那么在这种情况下浏览器会有一个默认缓存策略(currentTime - last-modified )*0.1

只有服务端没有返回明确的缓存策略时才会激活浏览器的启发式缓存策略

HTTP Heuristic Caching (Missing Cache-Control and Expires Headers) Explained | Paul Calvano

👉🏻 其他补充

  • 协商缓存想要配合强缓存使用,如果不开启强缓存使用,协商缓存没有意义
  • 大部分web服务器默认开启协商缓存,且是同时开启last-modifiedEtag

👉🏻 注意场景

1. 分布式系统里last-modified需要保持一致,以免负载到不同的机器导致比对失败,从而返回新资源。

2. 分布式系统尽量关闭掉Etag,因为每一台服务器生成的Etag是不同的

用户行为对缓存的影响

用户操作Expires/Cache-ControlLast-Modied/Etag
地址栏回车有效有效
页面链接跳转有效有效
新开窗口有效有效
前进回退有效有效
F5刷新无效有效
Ctrl+F5强制刷新无效无效

 参考资料

前端百题斩之一文了解HTTP缓存 | Expires、Last-Modified、Etag缓存控制 |

304状态码详解(协商缓存) | 深入理解浏览器缓存机制 | 扒一扒浏览器缓存机制 |

HTTP相关知识点整理 | 浏览器的缓存机制 | 能不能说一说浏览器缓存 |

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

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

相关文章

Midjourney教程古风人像类

古风图像的特点: 人物发型多为飘逸的长发,或是精致的盘发; 人物服装多为飘逸的长袍、长裙; 整体画风以水墨、水彩、工笔为c主,线条写意,色彩清新淡雅; 背景中多用花鸟、亭台楼阁、桃林等构建氛…

抖音seo矩阵系统源码|需求文档编译说明(三)

文章目录 批量剪辑工具技术源码框架 短视频SEO矩阵系统源码技术开发,遵循步骤抖音矩阵系统源码搭建功能 开发语言及开发环境 抖音账号矩阵系统源码搭建包括以下步骤 概要 ​​抖音seo源码,抖音矩阵系统如何使用源码二次开发,开发的功能有那些…

RT-Thread内核介绍

目录 三、RT-Thread内核介绍 3.1、内核框架 3.1.1、线程调度 3.1.2、时钟管理 3.1.3、线程间同步 3.1.4、线程间通信 3.1.5、内存管理 3.1.6、I/O 设备管理 3.2、RTT内核启动流程 3.2.1、汇编阶段 3.2.2、C阶段 3.2.3、rtthread_startup函数 3.2.4、创建主线程 三、…

jupyter notebook内核挂掉的解决方案

今天在运行notebook时报错 “jupyter notebook内核挂掉了”查找发现是下面这一句出的错,这是pytorch深度学习实战中的一个例程,读取三维体素文件并把其中的一张当作图片显示出来 plt.imshow(vol_arr[50]) 完整代码如下 import torch torch.set_printo…

决策树精讲

一、决策树的构造 决策树的构造是一个递归的过程,有三种情形会导致递归返回:(1)当前结点包含的样本全属于同一类别,这时直接将该结点标记为叶结点,并设为相应的类别;(2)当前属性集为空,或是所有样本在所有…

消息队列选型——为什么选择RabbitMQ

前言 MQ消息是目前分布式系统必不可少的组件,但是面对市面上众多的MQ组件,我们该用什么呢?我以实际项目的需求触发,介绍今天的主角——rabbitMQ。同时也会告知又有哪些优势和不足。事不宜迟,就开始今天的学习吧 目录…

ghost cms配置qq邮箱

背景: 在ghost cms中使用qq邮箱作为注册、登录、订阅等邮件发送方。 1 修改配置 在config.*.json文件中,添加mail配置 "mail": {"from": "xxxxxxqq.com","transport": "SMTP","options"…

Qt6 FFmpeg入门1 - 环境配置

目录 环境配置ffmpeg 下载qt 配套环境配置代码测试 环境配置 文章更新时间:2023/06/24 ffmpeg 下载 由于大部分的关于配置 ffmpegqt 环境的文章都停留在 2021 年,且许多方法均已过时,现在介绍一个最新的方法,并分析槽点供大家参考…

ElementUI在对话框中新增数据,使用rules校验规则进行校验,再点击完修改之后,在进行新增校验会报错

1.新增与修改使用同一个对话框,当修改完成一条数据后,重新打开新增的对话框,通过ElementUI的rules检验会报错 解决方案:在对应的rules校验中每个字段添加trigger: blur 即可解决上述问题,注意:下面的xxx代表需要校验的…

设计模式-05.01-行为型-观察者模板

观察者模式【常用】 我们常把 23 种经典的设计模式分为三类:创建型、结构型、行为型。前面我们已经学习了创建型和结构型,从今天起,我们开始学习行为型设计模式。我们知道,创建型设计模式主要解决“对象的创建”问题,…

工具篇7--RocketMq消息模型介绍

文章目录 前言:一、RocketMq是什么?二、RocketMq 模型介绍:1.RocketMq 模型图:2.RocketMq 生产者:2.1 生产者消费发送流程:2.2 生产者消息发送:2.2.1 同步发送普通消息:2.2.1 异步发…

AI大模型及算力要求

AI大模型对算力的要求非常高,需要高性能的硬件设备和分布式训练技术来支持。随着AI技术的不断发展,未来可能会出现更大、更复杂的模型,对算力的要求也将更高。今天和大家分享几个大模型及算力要求,希望对大家有所帮助。北京木奇移…

DETR系列:RT-DETR实战部署

上篇文章介绍RT-detr的论文内容(RT-DETR 论文解析),本篇文章介绍算法复现、tensorRT加速、python调用部署、训练等方法。 RT-DETR实战部署 1.复现模型详情2.环境准备3.训练4.部署5.测试 1.复现模型详情 本次复现主要测试下表中RT-DETR-R50和…

Kafka集群模式核心概念

文章目录 1.Kafka集群模式下Broker|主题|分区|副本的概念1.1.Broker|主题|分区|副本的概念1.2.创建一个Topic指定3个副本数1.3.多副本的Topic详细信息描述 2.集群模式下以消费者组消费Topic中各分区消息的概念2.1.分消费者组消费各分区的概念2.2.集群模式下消息的发送和消费 3.…

Go 语言中 Context 的作用和使用方法详解

KDP(数据服务平台)是一款由 KaiwuDB 独立自主研发的数据服务产品,以 KaiwuDB 为核心,面向 AIoT 场景打造的一站式数据服务平台,满足工业物联网、数字能源、车联网、智慧产业等行业核心业务场景下数据采集、处理、计算、…

在Azure SQL DB/Azure托管实例里快速查询各数据库大小以及每个数据库下表的大小

目录 (一)前言 (二)正文 1. 环境: 2. 查看实例下每个数据库的空间大小 (1) SQL语法 (2)运行结果 3. 查看特定数据库下每张表的大小 (1)SQ…

一个sql中的一张表,最多只会走一个索引吗

目录 先给结论 做实验 1.根据时间范围查询 什么是key_len? 2.根据时间范围和 is_delete 查询 最左匹配原则 2.根据时间范围和 blog_type 查询 如果加上id会怎么样 并不是索引一定会走 1.IN子表数量过多 2.单次查询超过30% 先给结论 先说结论,…

设计模式第14讲——享元模式(Flyweight)

目录 一、什么是享元模式 二、角色组成 三、优缺点 四、应用场景 4.1 生活场景 4.2 java场景 五、代码实现 5.0 代码结构 5.1 Bike——抽象享元类(FlyWeight) 5.2 具体享元类(ConcreteFlyWeight) 5.3 BikeFactory——享元…

layui框架学习(28:穿梭框模块)

Layui模块中的穿梭框模块transfer主要支撑穿梭框组件的显示、交互等操作。所谓穿梭框是指左右各有一个复选框列表,可以将左侧选中的项目移动到右边,后者将右侧的选中项移回左边的控件,其样式类似下图所示(参考文献5-6)…

TI AM62x工业开发板规格书(单/双/四核ARM Cortex-A53 + 单核ARM Cortex-M4F,主频1.4GHz)

1 评估板简介 创龙科技TL62x-EVM是一款基于TI Sitara系列AM62x单/双/四核ARM Cortex-A53 单核ARM Cortex-M4F多核处理器设计的高性能低功耗工业评估板,由核心板和评估底板组成。处理器ARM Cortex-A53(64-bit)主处理单元主频高达1.4GHz,ARM Cortex-M4F实…