首页/文章/http-网络

浏览器的缓存策略

2022-11-22
430015 分钟
...

缓存可以说是性能优化中简单高效的一种优化方式了。

一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。

对于一个数据请求来说,可以分为 网络请求、后端处理、浏览器响应 三个步骤。浏览器缓存可以帮助我们在第一和第三步骤中优化性能。

怎么实现缓存呢,缓存在哪?

  • service worker

运行在浏览器背后的独立线程,一般可以用来实现缓存功能。传输协议必须是https,因为它有涉及到请求拦截,所以必须使用https来保障安全。service worker的缓存和浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配、如何读取缓存、并且缓存是持续性的。

说了那么多,都是理论上的介绍,那么在实际上面它如何实现缓存功能呢?

1. 先注册Service Worker

2. 监听到install事件以后就可以缓存需要的文件

3. 用户下次再访问就可以通过拦截请求的方式查询是否存在缓存,存在缓存就直接读取缓存文件,否则请求数据

  • memory cache

内存中的缓存,主要包含当前页面中已经抓取到的资源(比如:页面已经下载的样式、脚本、图片等)。读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。就是我们关闭tab页面,内存中的缓存也就释放了。

那么这个时候有个问题,既然内存缓存很高效,我们是不是让数据都存放在内存中?

NO NO NO !!! 这个是万万不能的,计算机中的内存一定比硬盘容量小的多,操作系统需要精打细算内存的使用,所以能让我们使用的内存并不多。

当我们访问一个页面再次刷新页面,打开控制台发现很多数据都来自于内存缓存。

内存缓存中有一块重要的缓存资源是preloader相关指令下载的资源。(<link rel="prefetch">)众所周知 preloader 的相关指令已经是页面优化的常见手段之一,可以一边解析js/css文件,一边网络请求下一个资源。

**但是要注意:**内存缓存在缓存资源时并不关心返回资源的HTTP缓存头Cache-Control是什么值,并且不仅仅是只对url做匹配,还有Content-Type,CORS做校验。

  • disk cache
  • 存储在硬盘中的缓存,读取速度慢点,但是什么都能存储在磁盘中,比之Memory Cache 胜在容量和存储时效性上。
  • 在所有的浏览器缓存上面 disk Cache 覆盖面基本是最大的。
  • 会根据 HTTP Header 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。
  • 并且即使在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据。绝大部分的缓存都来自disk Cache。
  • push cache

推送缓存,是HTTP/2中的内容,当以上三种缓存都没有命中时,它才会被使用。只在会话中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在谷歌浏览器中只有5分钟左右,而且它并非严格执行HTTP请求头中的缓存指令。

如果以上四种缓存都没有命中的话就只能重新请求数据了。

看过以上四种缓存位置,产生了一个问题,浏览器会把哪些文件丢在内存中,哪些文件丢在硬盘中呢?

  • 对于大文件来说,大概率是不存储在内存中的
  • 当前系统内存使用率高的话,文件优先存储进硬盘。

缓存过程是怎样的呢?

浏览器与服务器的通信方式为应答模式。(浏览器发起请求 -> 服务器响应请求)

那么浏览器怎么确定这个资源该不该被缓存呢,如何去缓存?

浏览器第一次向服务端发起请求后拿到请求结果后,浏览器会将请求结果和缓存标识存入浏览器缓存中, 浏览器对于缓存的处理是根据第一次请求资源时返回的请求头来确定的。

总结:

  • 浏览器每次发起请求,都会先在浏览器缓存中查找有木有当前的请求结果和缓存标识。
  • 浏览器每次拿到请求结果都会将请求结果和缓存标识存放在浏览器缓存中。

什么是强缓存?

不会向服务器发送请求,直接从缓存中读取资源。可以在控制台Network选项看到该请求返回200状态码,并且size显示disk cache或者memory cache。

强缓存通过设置两种HTTP Header实现:ExpiresCache-Control

  • Expires

          缓存过期时间。用来指定资源到期的时间。(在响应请求时告诉浏览器在过期时间前可以直接从缓存中存取数据,无需再次请求)

**          注意:受限于本地时间,如果修改了本地时间,可能会造成缓存失效。**

  • Cache-Control

          控制网页缓存。有多种指令可以使用。

指令解释
public表示响应可以被客户端和代理服务器缓存(所有内容都将被缓存)
private响应只能被客户端缓存(默认取值)
max-age=30缓存30秒后就过期,需要重新请求
s-maxage=30覆盖max-age,作用一样,只在代理服务器端有效
no-store不缓存任何响应
no-cache资源被缓存,但是立即失效,下次会发起请求验证资源是否过期
max-stale=3030秒内即使缓存过期,也使用该缓存
min-fresh=30希望在30秒内获取最新的响应

总结:

**      强缓存判断是否缓存的依据来自于是否超出某个时间或者时间段,而不关心服务器端文件是否已经更新。这个可能会导致加载文件不是服务器端最新的内容。**

什么是协商缓存?

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存。

可以通过设置两种 HTTP Header 实现:Last-ModifiedETag

  • Last-Modified && if-Modified-Since

          a. 浏览器第一次访问资源,服务器返回资源的同时,在response header中添加Last-Modified这个header (值为这个资源在服务器上的最后修改时间),浏览器接收缓存资源和header。

          b. 当再次请求这个资源,浏览器检测到有Last-Modified这个header,就会添加if-Modified-Since这个header,值为Last-Modified的值

          c. 服务器再次接收到这个资源请求,会根据if-Modified-Since的值与服务器中该资源的最后修改时间做对比

                  如果没有变化,返回304状态码和空的响应体,直接从缓存读取

                  如果小于服务器中该资源的最后修改时间,说明文件有修改,返回新的资源文件和200状态码

**        但是Last-Modified也有缺点:**

          如果本地打开缓存文件,即使没有对文件进行修改,也还是会造成Last-Modified的值被修改,服务端不能命中缓存导致发送相同的资源;

          因为Last-Modified只能以秒计时,如果在不可感知的时间内完成修改文件,那么服务端会认为资源还是没有修改,不会返回正确的资源。

  • ETag && if-None-Match

ETag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)。只要资源有变化,ETag就会重新生成。

          浏览器在下一次加载资源向服务器发起请求会将上一次返回的ETag值放在request header里的if-None-Match,服务器只需要比对客户端传来的if-None-Match跟服务器上该资源的ETag是否一致,来判断服务端的资源是否更新。

                如果对上,直接返回304,知会客户端直接使用本地缓存

                如果有差异,将资源包括新的ETag重新发给客户端。

Last-Modified 和 ETag 有什么区别呢?

  • 精确度上:ETag 优于 Last-Modified
  • 性能上:Last-Modified 要优于 ETag,因为 Last-Modified 只需要记录时间,而 ETag 需要服务器通过算法来计算出一个hash值。
  • 优先级上:服务器校验优先考虑 ETag

缓存机制

「强制缓存」优先于「协商缓存」进行。

如果「强制缓存」生效,则直接使用缓存;如果不生效则进行「协商缓存」,「协商缓存」由服务器决定是否使用缓存。

如果「协商缓存」生效,则返回304,继续使用缓存;如果「协商缓存」失效,那么代表该请求的缓存失效,返回200,重新返回资源和缓存标识,再次存入浏览器缓存中。

如果什么缓存策略都没设置,浏览器会采用一个启发式的算法,通常会取响应头中的Date减去 Last-Modified 的值的10%作为缓存时间。

缓存在实际应用中有哪些场景呢?

  • 频繁变动的资源

使浏览器每次都请求服务器,然后配合 ETag 或者 Last-Modified 来判断资源是否有效。虽然不能节省请求数量,但是能显著减少响应数据大小。

Cache-Control: no-cache
  • 不常变动的资源

给它们的Cache-Control配置一个很大的 max-age=31536000(一年),这样浏览器之后请求相同的url会命中强制缓存。

为了解决更新问题,需要在文件名或者路径中添加hash,版本号等动态字符,从而达到更改引用url的目的,让之前的强制缓存失效。(jquery.3.3.3.min.js、lodash.min.js都采用这个模式)

Cache-Control: max-age=31536000

用户操作对于缓存有什么影响呢?

打开网页,地址栏输入地址:查找disk cache中是否有匹配,如果有则使用,没有则发送请求

普通刷新(F5):因为tab并没有关闭,因此memory cache是可用的,会被优先使用,其次才是 disk cache

强制刷新(Ctrl+F5):浏览器不使用缓存,因此发送的请求头均带有 Cache-Control: no-cache (Pragma: no-cache 为了处理兼容),服务器直接返回200和最新内容。

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
http-网络2025-10-27
frp-内网穿透详解
1\. 简介与工作原理 frp(Fast Reverse Proxy)是一个高性能的反向代理 / 内网穿透工具。典型部署模式: 在 公网 VPS 上运行 (服务端),监听来自 的 出站持久连接 (控制端口,通常 7000)。 在 内网机器 上运行 (客户端),与 frps 建立长连接并注册若干映射(如 tcp/http)。 当外部请求到达 frps(公网),frps 根据路由规则把流量转发回对应的 frpc 连接,再由 frpc 转发到...
学习
http-网络2025-10-13
内网穿透介绍
&nbsp; 1\. 简要概念与为什么需要内网穿透 大多数家庭/公司网络在私有网(RFC1918)后面,通过 NAT 共享一个公网 IP。NAT 允许内网对外发起连接,但阻止公网主动连入。 内网穿透 就是建立从公网到内网的可达通道,常用于:Webhook 回调、远程演示、远程管理、IoT 设备接入、远程调试等。 2\. 核心原理(三行总结) 反向连接 :内网主动连到公网穿透服务器,建立一条"回路"。 中继/代理 :穿透服务器把外部流量中...
学习
http-网络2025-08-06
按下回车后网页是怎么出来的
当你在浏览器中输入一个网址,比如 ,然后按下回车键,几秒钟后页面就完整地呈现在你眼前。这个看似简单的操作,背后其实是一整套精密协作的网络机制在起作用。本文将带你从基础讲起,理解 Web 开发中最重要的网络知识,帮助你搞清楚: 数据是如何从服务器传到你的电脑,并最终变成网页的? 一、互联网通信的分层模型:OSI 七层模型 为了管理复杂的网络通信,工程师们提出了一个通用的参考模型—— OSI 七层模型 。它把整个通信过程划分为七个层次,每一...
学习面试
http-网络2025-06-20
MQTT与HTTP在物联网中的比较:为什么MQTT是更好的选择
简介: 通过上述分析,可以看出MQTT在物联网应用中的确是更好的选择。其高效的通信模型、低带宽消耗、稳定的连接保持机制以及可靠的消息质量保证,使其在各种物联网场景中都能表现出色。开发者在设计和实现物联网系统时,应优先考虑采用MQTT协议,以充分发挥其在资源受限环境下的优势,提升系统的整体性能和可靠性。 【杂谈】 MQTT与HTTP在物联网中的比较:为什么MQTT是更好的选择 在物联网(IoT)应用中,选择合适的通信协议是实现高效、可靠数...
学习
http-网络2025-03-04
网络代理详解
一、 的基础概念 1\. 什么是代理? 代理是一种通过中间服务器来帮助 访问目标服务器的技术。代理服务器位于客户端与服务器之间,充当两者的中介,从而实现客户端和服务器之间的隔离。用户的所有请求经过代理后,再发往目标服务器,而目标服务器的响应则返回代理,再由代理传递给用户。 2\. 网络代理的工作流程 在基本的网络代理工作流程中, 扮演了“请求转发者”和“响应返回者”的角色: 1. 客户端请求 :客户端将请求发送到代理服务器,而不是直接发...
学习面试
http-网络2024-11-29
没有koa的cors你怎么处理跨域?
关联问题: JSONP有何局限性 CORS如何处理复杂请求 代理在生产环境效果如何 前言 “金九银十”的秋招,就像是落进池塘的羽毛,连点水花都没砸起来。已读不回是常态,能给面试已是情分,能拿offer的更是少之又少。可怜我在寒潮来临的深秋之际,也只得哀叹一句“越来越冷了啊...” 不过人总是要吃饭的,所以再怎么冷,卖炭翁也得卖炭,牛马攻城狮也得“攻城”,既是为了填饱肚子,也是为了“春天”做准备。所以今天为各位前端工程狮细聊一下前端面试中...
学习面试

评论

请登录后发表评论

去登录
加载评论中...

目录