跳到主要内容
约 13 分钟6 张卡

CDN

CDN(Content Delivery Network,内容分发网络)通过分布在不同位置的节点,把内容交付给用户。可缓存的响应可以在边缘节点复用,减少用户到源站的往返和源站负载;不能缓存的请求,也可能通过连接复用、路由优化等方式改善传输。

前端接入 CDN 后,仍要回答哪些内容能共享、不同请求是否会拿到同一份响应,以及新版本怎样替换旧版本。相同资源有时快、有时慢,也需要结合缓存命中、节点和回源链路判断,不能只看文件是否“放到了 CDN 上”。

1. 面试核心​

先记住这几条,再读正文
  • CDN 通过节点分发和内容复用减少远距离传输与回源,但“最近节点”是调度和网络路径的结果,不一定是地图上距离最近的机房。卡 · 节点分发与回源
  • 边缘未命中不一定直接请求源站,还可能访问上层缓存;大量冷请求则需要关注请求合并、回源限流和源站容量。卡 · 节点分发与回源
  • 公开、可复用且有明确更新规则的内容适合共享缓存。图片、脚本和字体是典型对象;用户私有数据不能因为 URL 看起来像静态文件就允许共享。卡 · 内容是否适合共享
  • 缓存键必须区分所有会改变响应的请求条件。忽略图片宽度、语言或用户身份,可能把错误响应交给另一个请求。卡 · 缓存键与响应变体
  • 内容版本 URL 与入口更新要配合发布:先让新资源可用,再更新 HTML 或清单,并保留仍被旧页面引用的资源。卡 · 资源版本与入口切换
  • 缓存清除只影响指定缓存层与范围,不会自动删除用户浏览器或 Service Worker 中的副本。卡 · 资源版本与入口切换
  • 同样设备与网络下的加载差异,要分别检查浏览器状态、节点命中、回源耗时和页面执行,不能看到白屏就直接归因于 CDN。卡 · 加载差异的定位
  • 动态加速不等于缓存动态响应。请求仍可回源执行,只优化连接与传输路径,业务计算和数据库等待仍然存在。卡 · 动态加速

2. 节点分发与回源​

源站是提供原始内容或业务响应的服务器;边缘节点是 CDN 接收用户请求、转发或复用响应的节点。用户访问资源域名时,接入配置会把请求引向 CDN,而不是直接访问源站。

接入可以通过 CNAME 等 DNS 配置完成,也可能由代理 DNS 记录或其他方式提供服务。CNAME 只说明名称指向关系,后续还要解析地址;具体过程见 DNS。DNS 调度可能考虑解析器位置、网络、节点负载和可用性;Anycast 则让多个位置使用相同地址,由网络路由选择路径。这些机制可以组合,不能把所有 CDN 都解释成“DNS 返回地理最近服务器”。

一次资源请求的关键步骤是:

  1. 用户建立到 CDN 节点的连接并发送请求。HTTPS 场景还涉及对应域名的证书和 TLS。
  2. 节点根据规则判断是否允许缓存,计算缓存键,查找可复用的响应。
  3. 找到满足条件的副本时直接返回;否则访问上层缓存或源站。
  4. 根据响应和缓存策略决定是否存储,再把内容交给客户端。

回源是 CDN 向源站获取或验证内容的过程。分层缓存会先让边缘查询上层节点,只有上层也没有可用内容时才回源,从而减少许多边缘节点重复请求同一个源站。具体层数和调度方式由服务实现决定。

缓存命中通常能减少源站工作,但命中不保证永远快:用户到节点的路径仍可能拥塞,大文件仍要传输,节点本身也有资源限制。未命中则增加了取回内容的过程,源站慢、跨区域链路慢或建立新连接,都可能拉长首字节时间。

3. 内容是否适合共享​

适合共享缓存的前提,是多个请求可以安全地复用同一个响应。 “静态”只是一个常见特征,并不是完整判断规则。

内容处理思路
带内容版本的 JS、CSS、图片、字体内容不随用户变化,可设置较长新鲜期,通过新 URL 发布新版本
公开商品介绍、公共文档、公开列表可以缓存,但要明确内容变化频率、允许的陈旧时间和失效方式
带用户余额、订单、私信的响应默认不进入共享缓存;使用合适的私有或禁止存储规则
登录响应、权限变化后的结果审查 Cookie、身份和权限语义,不依赖文件后缀判断
下载、视频分段、按尺寸变换的图片可以缓存,但要正确区分版本、Range 或变换参数等条件
实时任务事件流需要持续转发,不能当成普通完整对象缓存;还需关注缓冲和超时

公共 JSON 或 HTML 也可能适合缓存,但某家 CDN 的默认规则未必自动缓存它们。应分别核对内容是否适合共享、平台是否把它列为可缓存对象、响应头与自定义规则最终如何生效,不能只加一个 public 就结束检查。

浏览器缓存和 CDN 是不同层。private、no-store、s-maxage 与条件请求的基础语义见 HTTP 缓存。配置平台规则时,还要确认是否有覆盖源站缓存指令的选项,避免把本应私有的响应强行共享。

CDN 能转发一个需要认证的请求,不代表可以把它的结果复用给所有用户。对于签名下载 URL,也要先定义权限检查发生在哪一层、每次命中是否仍会鉴权,再决定签名参数是否进入缓存键。不能为了提高命中率直接删掉身份相关参数。

4. 缓存键与响应变体​

缓存键是缓存定位一份响应时使用的标识。它通常包含 URL,并可能根据平台规则纳入请求方法、查询参数、请求头或其他维度。缓存键相同,意味着系统准备把这些请求视为可以复用同一响应。

例如 /image?id=7&width=200 和 /image?id=7&width=800 对应不同尺寸。如果缓存键丢掉 width,先访问 200 像素版本的用户可能让后来的请求也拿到小图;如果把每次都变化、又不影响内容的追踪参数都放入键,同一张图则会散成许多副本,降低命中率。

判断是否删除参数,要问源站是否真的忽略它。还要检查请求头:如果响应依赖语言、压缩编码或 Origin,缓存也必须正确区分。标准 Vary 的含义见 HTTP 缓存;具体 CDN 对哪些 Vary 值生效、是否需要自定义缓存键,应以平台能力与配置为准,不能假定任意响应头都会自动参与匹配。

下面用一个受限的请求规则展示这个决定。约定 /public/ 仅提供公开内容,内容不依赖请求头或 Cookie;查询参数只有 utm_source 被源站完全忽略。其他查询参数及其顺序都保留。代码运行在持有请求信息的服务端环境,返回 null 表示跳过这条共享缓存规则。

export function publicCacheKey(request) {
const url = new URL(request.url);
if (request.method !== "GET") return null;
if (url.protocol !== "https:" && url.protocol !== "http:") return null;
if (!url.pathname.startsWith("/public/")) return null;
if (request.headers.has("authorization") || request.headers.has("cookie")) return null;
url.searchParams.delete("utm_source");
url.hash = "";
return `GET ${url.origin}${url.pathname}${url.search}`;
}

/public/image?id=7&width=200&utm_source=a 与追踪来源为 b 的请求会得到相同键,width=800 则不同。这里的 URL 参数解析与序列化也要求源站按一致的 URL 语义处理请求;如果源站区分原始编码形式或重复参数顺序,就要保留相应差异,不能擅自归一化。

这个函数只计算一个候选键。真正存储响应前,仍要检查状态码、缓存指令、Set-Cookie、响应大小和业务范围;也没有实现过期、条件请求、并发合并或驱逐策略。它不是任何 CDN 产品的完整默认缓存键,更不能直接套到用户接口上。

缓存投毒是让错误或恶意响应进入共享缓存,并被后续用户复用。它可能来自源站依据某个请求头生成响应,而缓存键没有区分该头,或者 CDN 与源站对路径、参数的解释不同。防护需要让请求规范化、响应生成和缓存匹配遵守一致规则,限制不受信任的输入对公共响应的影响;命中率提高不能以响应隔离失效为代价。

5. 新鲜度、清除与版本发布​

5.1 新鲜期与实际驻留​

缓存 TTL 表示响应在相应规则下可以保持新鲜多久,不承诺节点一定把它保留到最后一秒。冷门对象可能因容量等原因提前被驱逐;不同节点也可能在不同时间缓存同一个资源。因此,即使 URL 和 TTL 相同,也不能推出所有用户都命中同一份缓存。

响应过期后可以重新获取,也可以用 ETag 等验证器向上游确认版本。验证仍有网络往返,命中和重新验证的耗时不同。允许使用陈旧副本的策略也应明确:公开内容可能容忍短暂过期,涉及权限或金额的数据则不能随意套用“源站故障就继续用旧数据”。

大量热门资源同时过期或清除后,大量请求可能集中回源。可以结合分层缓存、同键请求合并、合理错开的有效期和源站限流减轻冲击;它们的适用范围取决于平台。某个节点内合并了请求,不代表全网所有节点只会发起一次回源。

5.2 资源版本与入口切换​

带内容版本的 URL 把“同一个名字的内容变了”改成“发布一个新名字”。例如旧 HTML 引用 app.a1.js,新 HTML 引用 app.b2.js,二者可以同时存在并各自缓存。只有在同一个 URL 永远对应同样内容时,长期缓存和不可变资源策略才容易成立。

发布顺序应是先上传新资源并验证可取,再更新引用它的 HTML 或清单。不能先发布新入口,等用户请求时才开始上传新文件。也不要更新入口后立刻删除旧文件:用户可能仍持有旧 HTML,或者已经打开的页面稍后才加载旧版本的动态分包。

HTML 和入口清单通常需要更短的新鲜期或重新验证,让用户及时得到新资源地址。回滚则恢复旧入口指向,前提是旧资源仍然保留。资源 URL 带版本,不代表接口协议也自动兼容,前后端滚动发布时仍要考虑已有页面继续使用旧代码。

5.3 清除范围与验证​

缓存清除是让指定范围的缓存副本失效或移除。平台可能提供按 URL、前缀、标签或全部清除等能力,实际范围和完成语义需要核对。

清除某个 CDN 的对象,不会同步清除浏览器缓存、Service Worker 缓存,也未必覆盖另一个 CDN 或上游缓存。自定义缓存键把一个 URL 分成多种变体时,清除请求也必须覆盖这些变体。源站如果仍返回错误内容,清除后还会再次缓存错误结果。

收到清除 API 的成功响应之后,仍要核对代表性节点和变体实际返回的版本、ETag 或内容摘要。只确认响应码正常,不能证明所有副本已经更新。版本 URL 可以降低对批量清除时效的依赖;紧急修复复用旧 URL 时,则要同时考虑浏览器中仍有效的旧副本。

6. 动态加速​

动态加速是在请求仍需要回源执行时,优化用户、边缘与源站之间的传输过程。它可以利用连接复用、较好的网络路径或传输协议减少建立连接与传输等待,但不会自动把用户专属响应变成可共享内容。

例如一个必须实时查询的订单接口,CDN 可以转发请求、复用到源站的连接;源站仍要完成鉴权、查询和业务计算。数据库等待占主要耗时时,只优化网络可能没有明显效果。边缘增加一跳也不保证必然更快,需要对实际用户地域、线路和接口测量。

如果把逻辑迁移到边缘执行,那属于另一项架构选择,还要讨论数据在哪里、访问数据库的距离以及一致性约束,不能与“接入 CDN”混为一谈。

7. 加载差异的定位​

相同设备和网络条件下,同一页面两次打开耗时不同,仍可能由缓存状态、连接状态和服务器负载变化造成。先把“白屏时间”拆成资源等待与页面执行,再验证 CDN 是否处于慢的那一段。

观察对象要比较的证据可以区分的问题
浏览器本地状态Network 中的内存/磁盘缓存、Service Worker、请求是否真正发出本地命中与 CDN 命中不是一回事
DNS 与连接解析、TCP/TLS、连接复用、协议新连接成本、节点或路径变化
请求身份与变体完整 URL、查询参数、Cookie、请求头、实际版本看似相同资源是否用了不同缓存键或绕过规则
首字节与缓存状态TTFB、Age、平台缓存状态头、请求 ID、节点信息冷缓存、过期验证、回源及节点负载
正文传输字节数、编码、传输耗时资源版本、压缩、带宽和丢包影响
收到之后的执行长任务、脚本错误、布局与绘制资源下载已经结束,页面仍未可用

例如平台报告一次 MISS、随后报告 HIT,并且源站日志只有第一次取回记录,就支持“后一次复用了边缘缓存”的判断。仅凭第二次 TTFB 小一些还不够,因为连接复用也可能改善耗时。缓存状态头的名称和语义是产品约定,例如 Cloudflare 使用 CF-Cache-Status;不要把演示代理自己的头当成真实平台状态。

Age 能帮助判断响应经过缓存的时间,但不是节点位置或用户体验指标;在多层缓存中还要结合上游来源解释。请求 ID、节点标识和回源日志能把浏览器观察与服务端记录关联起来。跨域 Resource Timing 的部分字段受 Timing-Allow-Origin 等条件限制,零值也不能独立证明命中。

排查时应比较冷、热请求,保存相同条件下的完整响应信息,并看多次采样及真实用户分布。给 URL 随意加随机参数可能把请求变成另一个缓存键,测到的就不再是原资源的命中情况。请求排队、关键资源发现和脚本执行的定位见 Web 资源加载。

8 · 面试题卡片​

本页题目与参考回答

8.1 CDN 如何加速资源访问,未命中时会发生什么?​

考察重点:请求调度、边缘缓存、分层缓存与回源。

相关内容:节点分发与回源、新鲜期与实际驻留。

参考回答

CDN 把请求调度到合适的节点,在允许时复用缓存响应,减少远距离传输与源站工作。 调度可能结合 DNS、网络路由、节点负载和可用性,不保证选中地理距离最近的位置。

节点未命中时可能先查上层缓存,再向源站获取或验证内容。大量冷请求可能集中回源,需要考虑分层、请求合并和源站容量。命中仍有客户端到节点的传输成本,不能保证所有请求都快。

8.2 哪些内容适合放在 CDN,哪些不适合共享缓存?​

考察重点:公共内容、缓存资格、身份隔离与更新规则。

相关内容:内容是否适合共享、缓存键与响应变体。

参考回答

公开且可复用、具有明确更新方式的响应适合共享缓存。 带版本的图片、脚本、样式和字体是典型对象,公共 HTML、JSON 也可以按规则缓存,但平台默认策略不一定覆盖它们。

用户余额、私信和订单等专属内容不能任意共享。应检查身份、Cookie、响应指令及平台覆盖规则;图片尺寸、语言等变化条件也要正确进入缓存匹配。请求可以经过 CDN 转发,并不等于响应可以被其他用户复用。

8.3 CDN 缓存键应包含哪些内容,为什么不能随意忽略查询参数?​

考察重点:响应变体、参数归一化、命中率与隔离正确性。

相关内容:缓存键与响应变体。

参考回答

缓存键应区分所有会改变可复用响应的请求条件。 URL、查询参数及必要的请求头等维度由业务和平台配置共同决定。忽略 width 会混用不同尺寸的图片;保留无意义随机参数又会制造大量副本。

删除或归一化参数前,确认源站确实按相同语义处理,尤其注意重复参数、编码形式和签名参数。还要核对 Vary 的实际支持情况;不能用提高命中率的理由破坏用户数据和响应变体的隔离。

8.4 前端使用 CDN 长期缓存资源后,怎样发布新版本和回滚?​

考察重点:版本 URL、入口引用、旧资源保留及清除边界。

相关内容:资源版本与入口切换、清除范围与验证。

参考回答

使用内容版本 URL,先让新资源可用,再更新 HTML 或清单的引用。 入口采用合适的短缓存或验证策略,旧资源保留到旧页面不再需要它们,尤其注意延迟加载的分包。

回滚恢复旧入口指向,并确认旧资源与接口仍可用。CDN 清除不会删除浏览器或 Service Worker 副本,自定义键的变体也要覆盖。清除后核对实际版本与内容,不能只看 API 返回成功。

8.5 网络和设备一致时,CDN 为什么仍可能造成资源加载时间不同?​

考察重点:缓存状态变化、节点与回源链路、证据归因。

相关内容:加载差异的定位。

参考回答

缓存命中、过期验证、回源和节点负载仍可能不同,连接也可能一次新建、一次复用。 先确认 URL、请求头和身份条件一致,再看浏览器缓存、节点信息、缓存状态头、TTFB 和源站记录,区分命中与回源。

相同设备网络不代表所有内部状态相同。若资源早已下载完成而页面仍白屏,还要检查脚本错误、执行长任务和渲染依赖,不能直接把全部延迟归给 CDN。多次采样比一次快慢对照更可靠。

8.6 CDN 动态加速与静态内容缓存有什么不同?​

考察重点:传输优化、缓存复用与业务执行成本。

相关内容:动态加速、内容是否适合共享。

参考回答

静态内容缓存复用已有响应,动态加速可以在仍然回源执行的前提下优化网络路径和连接。 订单接口的身份校验与查询仍由服务端完成,不能因此缓存为所有用户共享的结果。

如果主要耗时在数据库或业务计算,网络优化收益可能有限;接入边缘也不保证必然更快。把业务逻辑迁移到边缘执行则是另一项设计,还要考虑数据位置和一致性。

9. 参考资料​

来源:Coding 101 原文 · 免费阅读,引用请保留出处。内容使用说明