浅谈浏览器的缓存机制

浏览器的存储 和浏览器的缓存不是同一个东西,本文谈谈浏览器的缓存机制

缓存的技术种类有很多,比如代理缓存浏览器缓存网关缓存负载均衡器内容分发网络等,它们大致可以分为两类: 共享缓存私有缓存共享缓存指的是缓存内容可被多个用户使用,如公司内部架设的Web代理;私有缓存指的是只能单独被用户使用的缓存,如浏览器的缓存 HTTP缓存 应该算是前端开发中最常接触的缓存机制之一,它又可细分为强制缓存协商缓存

浏览器缓存(http缓存)

浏览器缓存也叫做 http缓存 ,浏览器的缓存机制指的是通过在一段时间内保留已接收到的 web 资源的一个副本,如果在资源的有效时间内,发起了对这个资源的再一次请求,那么浏览器会直接使用缓存的副本,而不是向服务器发起请求。

简单理解就是本地(浏览器)缓存了HTTP响应,以便后续复用,减少向服务端的请求。使用 web 缓存可以有效地提高页面的打开速度,减少不必要的网络带宽的消耗。

缓存策略

通常浏览器缓存策略分为两种:强缓存协商缓存,并且缓存策略都是通过设置 HTTP Header 来实现的。

强缓存

使用强缓存策略时,如果缓存资源有效,则直接使用缓存资源,不必再向服务器发起请求。

强缓存策略可以通过两种方式来设置,分别是 http 头信息中的 Expires 属性和 Cache-Control 属性。
Expires 服务器通过在响应头中添加 Expires 属性,来指定资源的过期时间。在过期时间以内,该资源可以被缓存使用,不必再向服务器发送请求。这个时间是一个绝对时间,它是服务器的时间,因此可能存在这样的问题,就是客户端的时间和服务器端的时间不一致,或者用户可以对客户端时间进行修改的情况,这样就可能会影响缓存命中的结果。
GMT 表示的是格林威治时间,和北京时间相差8小时。

js 复制代码
Expires:Fri, 27 Oct 2023 07:55:30 GMT
// GMT 表示的是格林威治时间,和北京时间相差8小时。
// 实际的是时间是:2023年10月27日15:55:30

Cache-Control Expires 是 http1.0 中的方式,因为它的一些缺点,在 http 1.1 中提出了一个新的头部属性就是 Cache-Control 属性,它提供了对资源的缓存的更精确的控制,这是一个相对时间。

js 复制代码
Cache-Control:max-age=600 // 单位是秒

Cache-Control 除了 max-age 属性之外,还有一些其他的属性:

  • no-cache:需要进行协商缓存,发送请求到服务器确认是否使用缓存。
  • no-store:禁止使用缓存,每一次都要重新请求数据。
  • public:默认设置。
  • private:不能被多用户共享。

现在基本上都会同时设置 ExpireCache-ControlCache-Control 的优先级别更高。

协商缓存

使用协商缓存策略时,会先向服务器发送一个请求,如果资源没有发生修改,则返回一个 304 状态,让浏览器使用本地的缓存副本,如果资源发生了修改,则返回修改后的资源。

协商缓存也可以通过两种方式来设置,分别是 http 头信息中的 EtagLast-Modified 属性。
Last-Modified 浏览器第一次请求资源的时候,服务器返回的 header 上会带有一个 Last-Modified 字段,表示资源 "最后修改" 的时间,是一个 GMT 的绝对时间。
当浏览器再次请求该资源时,请求头中会带有一个 If-Modified-Since 字段,这个值是第一次请求返回的 Last-Modified 的值。服务器收到这个请求后,将 If-Modified-Since 和当前的 Last-Modified 进行对比。如果相等,则说明资源未修改,返回 304,浏览器使用本地缓存。
但这个会有缺点:
1、最小单位是秒。也就是说如果我短时间内资源发生了改变,Last-Modified 并不会发生变化;
2、期性变化。如果这个资源在一个周期内修改回原来的样子了,我们认为是可以使用缓存的,但是 Last-Modified 可不这样认为。因此,引入了一个 "Etag" 。 Etag Etag 一般是由文件内容 hash 生成的,也就是说它可以保证资源的唯一性,资源发生改变就会导致 Etag 发生改变。
在浏览器第一次请求资源时,服务器会返回一个 Etag 标识。当再次请求该资源时, 会通过 If-no-match 字段将 Etag 发送回服务器,然后服务器进行比较,如果相等,则返回 304 表示未修改。

Last-Modified Etag 是可以同时设置的,服务器会优先校验 Etag ,如果 Etag 相等就会继续比对 Last-Modified ,最后才会决定是否返回 304

总结

当浏览器再次访问一个已经访问过的资源时,它会这样做:

  1. 看看是否命中强缓存,如果命中,就直接使用缓存了;
  2. 如果没有命中强缓存,就发请求到服务器检查是否命中协商缓存;
  3. 如果命中协商缓存,服务器会返回 304 告诉浏览器使用本地缓存;
  4. 否则,返回最新的资源。

缓存位置

从缓存位置上来说分为4种,并且各自有优先级,当依次查找缓存且都没有命中的时候,才会去请求网络。Service WorkerMemory CacheDisk CachePush Cache
Service Worker Service Worker 是运行在浏览器背后的独立线程,一般可以用来实现缓存功能
使用 Service Worker的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。

diff 复制代码
实现步骤:
- 注册Service Worker
- 监听到install事件以后就可以缓存需要的文件
- 在下次用户访问的时候就可以通过拦截请求的方式查询是否存在缓存,存在缓存直接读取文件,否则就去请求数据

Memory Cache Memory Cache 是内存中的缓存,主要包含的是当前页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片等。
读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。一旦我们关闭Tab页面,内存中的缓存也就被释放。 Disk Cache Disk Cache 是存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中,比 Memory Cache 胜在容量和存储时效性上。
在所有浏览器缓存中,Disk Cache 覆盖面基本是最大的。它会根据 HTTP Herder 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。并且即使在跨站点的情况下,相同地址的资源一旦被硬盘缓存下来,就不会再次去请求数据。绝大部分的缓存都来自 Disk Cache。 Push Cache Push Cache(推送缓存)是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。
它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在Chrome浏览器中只有5分钟左右,同时它也并非严格执行HTTP头中的缓存指令。
如果以上四种缓存都没有命中的话,那么只能发起请求来获取资源了。
为了性能上的考虑,大部分的接口都应该选择好缓存策略(强缓存和协商缓存策略)。

用户行为对缓存的影响

用户在浏览器如何操作时,会触发缓存策略,主要有 3 种:

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

2、普通刷新 (F5):因为 tab标签 并没有关闭,因此 memory cache 是可用的,会被优先使用(如果匹配的话)。其次才是 disk cache。

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

参考文献

相关推荐
范文杰1 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪1 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪1 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy2 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom3 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom3 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom3 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom3 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom3 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试
LaoZhangAI4 小时前
2025最全GPT-4o图像生成API指南:官方接口配置+15个实用提示词【保姆级教程】
前端