JS- HTTP 缓存机制与 CDN 原理

33 阅读7分钟

前言

在前端性能优化中,“网络请求”是耗时大户。如何让浏览器“少请求”甚至“不请求”后端接口,是提升页面加载速度的关键。本文将带你深入理解 浏览器 HTTP 缓存 的两道防线(强缓存与协商缓存),以及 CDN 是如何让资源“飞”到用户面前的

一、 浏览器缓存机制全貌

浏览器缓存的本质是:当浏览器发起请求时,首先在本地查找是否有缓存副本,根据缓存标识决定是否使用副本或向服务器发起新请求。

整个缓存策略可以概括为两步走:

  1. 强缓存:浏览器直接判断是否有效,有效则直接用,不发请求。
  2. 协商缓存:强缓存失效后,浏览器发送请求询问服务器“资源变没变”,没变就用缓存(304),变了就返回新资源(200)。

二、 第一道防线:强缓存

强缓存不需要与服务器通信。命中强缓存时,Chrome 控制台的 Network 选项中 Status 会显示 200 (from memory cache)200 (from disk cache)

1. Expires (HTTP/1.0)

  • 原理:服务器返回一个绝对时间戳(例如:Wed, 22 Oct 2025 08:41:00 GMT)。如果当前本地时间小于这个时间,则缓存有效。
  • 缺陷:它严重依赖客户端本地时间。如果用户修改了本地时间,或者客户端与服务端时间不同步,会导致缓存判断出错。

2. Cache-Control (HTTP/1.1)

为了解决 Expires 的缺陷,HTTP/1.1 新增了 Cache-Control 字段。

  • 原理:通过 max-age=xxx 设置相对时间(单位:秒)。例如 max-age=3600 代表资源在 3600 秒内有效,与本地时间无关。
  • 优先级:当 Cache-ControlExpires 同时存在时,Cache-Control 优先级更高

Cache-Control 常用取值辨析:

指令含义
public所有内容都将被缓存(客户端和代理服务器/CDN 均可缓存)。
private默认值。只有客户端(浏览器)可以缓存,代理服务器不可缓存。
no-cache客户端缓存内容,但每次使用前必须向服务器发起协商缓存验证
no-store禁止任何缓存。每次都向服务器发起全新的请求。
max-age=x缓存内容将在 x 秒后失效。

三、 第二道防线:协商缓存

当强缓存失效(max-age 过期)或设置了 no-cache 时,浏览器会携带缓存标识向服务器发起请求,由服务器决定是否使用缓存。

1. 结果状态码

  • 304 Not Modified:服务器告诉浏览器:“资源没变,你继续用本地缓存吧”。
  • 200 OK:服务器告诉浏览器:“资源变了,这是最新的数据”,并更新本地缓存和标识。

2. 标识一:Last-Modified / If-Modified-Since

  • Last-Modified:是服务器响应请求时,返回给浏览器该请求资源在服务器最后被修改的时间。

  • If-Modified-Since:浏览器再次请求时,自动带上上次的 Last-Modified 值。通过这个值告诉服务器该资源上次请求返回的最后被修改时间。服务器收到该请求后,会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件。

  • 不足

    • 精度问题:时间单位是。如果文件在 1 秒内被修改多次,服务端无法感知。
    • 内容未变:如果仅仅是打开文件保存了一下(修改时间变了),但内容没变,也会导致缓存失效,浪费带宽。

3. 标识二:ETag / If-None-Match (优先级更高)

为了解决 Last-Modified 的不足,HTTP/1.1 引入了 ETag(实体标签)。

  • ETag:服务端将要返回给客户端的数据通进行哈希计算生成一个Etag字符串(类似文件指纹)。只要内容变了,ETag 必变。

  • If-None-Match:浏览器再次请求时,会将上次请求返回的Etag值包装在If-None-Match中,服务端会检测If-None-Match值是否和Etag一致,如果一致则返回304。

  • 不足

    • 性能损耗:生成 ETag 需要额外的计算开销(特别是大文件)。
    • 分布式问题:在多台服务器集群中,如果不同服务器对同一个文件的 ETag 计算算法或 inode 不同,可能导致 ETag 不一致而缓存失效。

总结:协商缓存对比

特性Last-ModifiedETag
依据文件最后修改时间文件内容哈希值
精度秒级(低)极高(字节级变化)
优先级
服务端消耗极低较高(需计算)

四、 跨越千里的加速:CDN 缓存

1. 什么是 CDN?

CDN(Content Delivery Network,内容分发网络)是一种分布式网络架构。简单来说,就是把你的资源“搬”到离用户最近的服务器上。

作用: 解决因地域、带宽、网络拥挤带来的访问延迟,提高响应速度。

2. 通信流程对比

🛑 不使用 CDN 的流程:

  1. 用户请求 DNS 解析域名。
  2. DNS 返回源站服务器 IP。
  3. 用户向该 IP 请求资源。
  4. 源站服务器返回资源。

✅ 使用 CDN 的流程:

  1. DNS 解析:用户向传统 DNS 服务器请求域名解析。

  2. CNAME 重定向:DNS 服务器将域名解析权交给 CNAME 指向的 CDN 专用 DNS 服务器。

  3. 智能调度:CDN 专用 DNS 服务器通过全局负载均衡器,根据用户的 IP 地址(地理位置)、运营商、服务器负载等情况,计算出离用户最近最优的节点

  4. 返回节点 IP:将该区域缓存服务器的 IP 返回给用户。

  5. 请求资源:用户向该缓存服务器发起请求。

    • 命中:如果这台服务器有资源,直接返回。
    • 回源:如果没有,它会向上一级或源站服务器请求资源(这就叫回源),拉取到本地缓存后,再返回给用户。

四、 面试题:当用户刷新页面(F5)和强制刷新(Ctrl+F5)时,浏览器缓存是如何工作的?

1. F5 刷新(普通刷新)

当你按下 F5 时,浏览器会认为:“虽然我本地有缓存,但我不太确定它是不是最新的,我去问问服务器。”

  • 请求头变化:浏览器会自动添加 Cache-Control: max-age=0

  • 结果:跳过强缓存阶段,直接进入协商缓存

    • 如果服务器发现资源没变,返回 304,浏览器继续用本地旧缓存。
    • 如果资源变了,返回 200 和新内容。

2.Ctrl + F5(强制刷新)

当你按下 Ctrl + F5 时,浏览器会认为:“我不要本地任何缓存,服务器你必须给我一份最新的!”

  • 请求头变化:浏览器会添加 Cache-Control: no-cachePragma: no-cache,并且不会携带 If-None-Match (ETag) 或 If-Modified-Since (Last-Modified)。
  • 结果:完全跳过所有缓存逻辑,状态码必定为 200,并重新下载资源。

补充:为什么“地址栏回车”和“F5”不一样?

这是很多人的误区。

  • 地址栏输入:是最高级别的缓存利用。只要 max-age 没过期,浏览器连服务器的门都不会敲,直接从内存或磁盘拿数据。
  • F5 刷新:是主动触发的校验行为。它强制浏览器去敲服务器的门,问一句:“嘿,我这东西还能用吗?”

💡 总结

  • 强缓存(Expires/Cache-Control)最快,直接不发请求。
  • 协商缓存(Last-Modified/ETag)次之,发请求确认,节省带宽。
  • CDN 让资源在物理距离上离用户更近。
  • 最佳实践:通常对 HTML 文件使用协商缓存(no-cache),确保用户及时获取最新引用;对 CSS/JS/图片等静态资源使用强缓存(max-age 设置很长)配合文件名 Hash(如 style.a1b2c.css)来实现版本更新。