HTTP 与 CDN

共 56 题
📑 题目列表 56 题
#
★★★

1. Cache-Control 与 immutable/max-age 在 hash 文件与版本目录策略的工程取舍

请说明 Cache-Control 中 max-age 与 immutable 在 hash 文件名和版本目录两种发布策略下的工程取舍?

  • Cache-Control 指令语义(max-age、s-maxage、immutable、no-cache、no-store)
  • 内容寻址(hash 文件名)与版本目录(/v1/)两种策略的缓存失效差异
  • 缓存层级与发布时的原子性

对带内容 hash 的文件(如 app-8f3a2b.js),资源内容与 URL 一一对应,内容变化则 hash 变化而 URL 改变,因此可以放心使用 Cache-Control: public, max-age=31536000, immutable 实现一年长缓存,永不重新验证,因为 URL 变化本身就是失效手段。而版本目录(/v1/app.js)中 URL 不变,发布时需显式改目录名或更新引用,若仍用长 max-age 且缓存未随发布清空,旧版本会滞留。immutable 表示内容在生命周期内绝不变,浏览器可跳过 revalidation,只在 hash 文件上安全;非 hash 文件使用 immutable 会导致旧内容长期滞留。工程取舍上,hash 文件追求"长缓存 + 不改即不重新请求",版本目录则需配合服务端缓存失效或版本号参数。

核心是"缓存内容是否随 URL 唯一确定"。hash 文件天然满足"URL 变才改内容",所以可以极致长缓存;版本目录内容与 URL 非一一对应,必须依赖发布时主动失效或短缓存,二者不可混用,否则出现缓存脏数据。

# hash 文件:nginx 配置
location /static/ {
  add_header Cache-Control "public, max-age=31536000, immutable";
}
# 版本目录:更保守,允许重新验证
location /v1/ {
  add_header Cache-Control "public, max-age=60, must-revalidate";
}
#
★★★

2. Service Worker Cache API 与 HTTP 缓存的协同

请说明 Service Worker 的 Cache API 与浏览器 HTTP 缓存如何协同工作,以及各自的优先级与适用场景?

  • Service Worker 拦截 fetch 的时机(在 HTTP 缓存之前)
  • Cache API 与 HTTP 缓存的层级关系
  • 缓存策略(cache-first、network-first、stale-while-revalidate)与 HTTP 头协同

Service Worker 的 fetch 事件处理器先于浏览器 HTTP 缓存执行,因此 SW 可以决定是直接返回 Cache API 中的响应、走网络还是放行让 HTTP 缓存接管。它们是两层缓存:SW 层(Cache API,应用层可控、可离线)与 HTTP 层(浏览器 disk cache,受 Cache-Control 控制)。二者协同时,SW 通常做"离线优先/网络优先"策略,而 HTTP 缓存负责命中已缓存资源。SW 放行后,浏览器会依据响应的 Cache-Control 决定是否存入 HTTP 缓存。工程上常见做法是 SW 用 cache-first 提供秒开与离线,同时配合 stale-while-revalidate 在后台更新缓存,而 HTTP 缓存对 hash 资源用长缓存兜底。

关键点是 SW 拦截在 HTTP 缓存之前,SW 拥有最终裁决权;SW 不愿管时 return fetch(event.request) 或直接返回,浏览器才进入 HTTP 缓存逻辑。两层缓存冗余但各司其职,SW 提供离线与精细策略,HTTP 缓存提供底层网络节省。

self.addEventListener('fetch', (e) => {
  e.respondWith(
    caches.match(e.request).then(cached => {
      const network = fetch(e.request).then(res => {
        const copy = res.clone();
        caches.open('v1').then(c => c.put(e.request, copy));
        return res;
      });
      return cached || network; // cache-first,网络兜底
    })
  );
});
#
★★★

3. CDN 缓存策略与回源机制

请说明 CDN 的缓存策略与回源机制,以及如何通过响应头控制 CDN 缓存行为?

  • CDN 缓存判定(Cache-Control/Expires 或 CDN 默认规则)
  • 回源(origin)触发条件:缓存未命中、过期、强制刷新
  • s-maxage 与 CDN 专用头(CDN-Cache-Control、Surrogate-Control)

CDN 是一个中间缓存层,位于用户与源站之间。当用户请求资源时,CDN 边缘节点先查本地缓存,命中则直接返回;未命中或过期则回源站拉取并缓存后再返回。CDN 根据响应头决定缓存时长:Cache-Control: s-maxage=3600 用于 CDN 缓存(s 指 shared cache),max-age 用于浏览器;CDN-Cache-Control / Surrogate-Control 是厂商扩展头,可精确控制 CDN 而不影响浏览器。回源会影响性能与成本,因此高命中率是关键。回源也可通过 Query 参数、Cookie 或 CDN 规则(如排除某些路径)绕过缓存。

CDN 是共享缓存,s-maxage 与 max-age 分离让 CDN 和浏览器缓存周期不同。回源机制是"缓存未命中才请求源站",优化命中率即减少回源;同时 CDN 支持缓存键(Vary、Cache Key)定制,避免同一 URL 因不同 Accept 头共享错误缓存。

// 响应头示例:CDN 缓存 1 小时,浏览器缓存 10 分钟
Cache-Control: public, max-age=600, s-maxage=3600
#
★★★

4. Cloudflare Cache API(Cache API)

请说明 Cloudflare Cache API 的用途、在什么场景下可用与不可用,以及它与浏览器 Cache API 的差异?

  • Cloudflare Cache API 的接口(cache.put/match/delete)
  • 可用范围(仅 Workers,且仅对缓存可缓存响应)
  • 缓存区分与 TTL

Cloudflare Cache API 运行在 Cloudflare Workers 内,允许你在边缘代码中主动写入、读取、删除 Cloudflare 的缓存对象,接口类似浏览器 Cache API(cache.put(url, response)cache.match(url)cache.delete(url))。它只能在 Workers 的 substrequest 场景使用(即通过 fetch 发出的子请求),不能直接缓存事件处理器返回的响应;且仅能缓存可缓存类型(如 GET、图片、CSS),且响应需带合法 Cache-Control 或 TTL。它适合对缓存做精细控制,例如手动缓存第三方 API 响应、按业务逻辑缓存、主动失效。与浏览器 Cache API 相比,它运行在边缘而非用户浏览器,供所有用户共享。

关键边界是 Cloudflare Cache API 只能操作"子请求"(通过 fetch 在 Worker 内发出的请求)的响应,而不是 Worker 主请求的响应;主响应需借助 Cloudflare 默认缓存或 Cache API 不可用。它是运维层缓存控制的编程化入口。

export default {
  async fetch(req, env, ctx) {
    const cache = caches.default;
    const url = new URL(req.url);
    let res = await cache.match(url.pathname);
    if (!res) {
      res = await fetch('https://api.example.com' + url.pathname);
      const headers = new Headers(res.headers);
      headers.set('Cache-Control', 'public, max-age=300');
      res = new Response(res.body, { headers });
      ctx.waitUntil(cache.put(url.pathname, res.clone()));
    }
    return res;
  }
};
#
★★★

5. stale-while-revalidate 在 CDN 缓存的工程价值

请说明 stale-while-revalidate(SWR)在 CDN 缓存中的工程价值及其与浏览器端 SWR 的区别?

  • stale-while-revalidate 指令语义(stale-while-revalidate 与 stale-if-error)
  • CDN 端 SWR 如何降低回源延迟
  • 与浏览器 SWR(数据请求层)的区别

Cache-Control: stale-while-revalidate=300 表示:缓存过期后,可以立即返回陈旧的缓存内容,同时后台异步向源站发请求更新缓存。这样用户无需等待回源,首字节延迟接近命中,同时缓存保持新鲜。它对 CDN 价值巨大:热门但更新频率不高的接口可在过期瞬间仍秒回旧数据,后台刷新,避免回源竞态与排队。stale-if-error=300 则在源站出错时继续返回陈旧数据用作降级。需注意这两者可能让客户端看到短暂旧数据,适合对一致性要求不极端的场景。浏览器数据请求层的 SWR(如 SWR 库)语义类似但作用在业务层,控制的是"用缓存数据渲染 + 后台重新请求"。

这是 CDN 提升命中率与感知性能的经典手段。核心 trade-off 是"短暂陈旧的代价 vs 高延迟/回源失败的代价"。对 CDN 而言它把"同步等待回源"变成"异步后台刷新",显著降低 TTFB。

// 响应头:CDN 缓存 10 分钟,过期后允许最多 5 分钟陈旧并在后台刷新
Cache-Control: public, max-age=600, stale-while-revalidate=300
#
★★★

6. CDN 节点选择与 Anycast 网络在边缘性能的应用

请说明 CDN 节点选择机制与 Anycast 网络如何提升边缘性能?

  • Anycast 与 Unicast 的区别
  • BGP 路由与最近节点选择
  • CDN 节点选择(DNS 解析、Anycast、健康检查)

Anycast 通过 BGP 路由协议让多个地理位置分布的 CDN 节点共享同一个 IP 地址,用户的请求到达最近/最优的节点再由路由决策返回。相比 Unicast(每个节点独立 IP,需 DNS 轮询或 geo 解析),Anycast 的优势是网络层自动选择最佳路径、天然具备高可用(某节点故障时 BGP 自动收敛到其他节点)、无需复杂 DNS 配置即可实现就近接入。CDN 节点选择通常结合 DNS 解析(geoDNS 返回最近节点 IP)与 Anycast(共享 IP 的 IP 层就近),配合边缘节点的健康检测与负载均衡。Anycast 的问题是路由可能不稳定(漂移),缓存命中率因节点变化受影响,但总体大幅降低 RTT。

Anycast 的核心是"同一 IP 多地可达,由网络路由决定目的地",这让"选择最近节点"下沉到网络层,无需应用层维护节点表;同时天然容灾。它是边缘性能的关键基础设施。

#
★★★

7. Cloudflare/CloudFront/Edge CDN 的边缘计算能力

请说明 Cloudflare、CloudFront 等边缘 CDN 的边缘计算能力及其在前端工程中的应用?

  • Cloudflare Workers / CloudFront Functions / Edge Functions
  • 边缘计算与 CDN 的关系
  • 边缘渲染、A/B 测试、请求改写、鉴权

现代 CDN 不仅是缓存层,还提供边缘计算能力:Cloudflare Workers(基于 V8,接近 JavaScript 运行时)、CloudFront Functions(轻量、短超时)与 Lambda@Edge、Fastly Compute@Edge、Vercel Edge Functions 等。它们的共同点是在离用户最近的边缘节点执行代码,处理请求、改写响应、做鉴权、聚合第三方 API、做 A/B 测试、服务端渲染(SSR)或预渲染(SSG)的一部分。由于代码在边缘且全球分发,避免了源站往返,延迟显著降低。边缘计算在性能上优于传统源站,但受限于资源(CPU/内存/超时)与平台模型,复杂逻辑仍应放回源站或 BFF。

边缘计算把"可在客户端或源站执行的逻辑"下沉到 CDN 边缘,兼顾性能与灵活性。前端工程里它常用于缓存控制、动态改写、鉴权、灰度与 SSR 加速,是"无服务器 + CDN"的融合。

#
★★★

8. 缓存预热、缓存失效与版本管理

请说明 CDN 缓存预热、缓存失效与版本管理在发布中的工程实践?

  • 缓存预热(Purge/Preload)的目的与方法
  • 缓存失效(Purge、版本号、URL 变更)
  • 版本管理策略与发布原子性

缓存预热(Cache Warm/Preload)是指发布后主动请求 CDN 边缘,把热点资源提前填充到缓存,避免发布瞬间大量回源造成"惊群"(stampede)。缓存失效(Purge/Invalidation)是主动删除 CDN 上旧缓存,可整站、按 URL 或按 Tag 批量失效。版本管理上,hash 文件名是最佳实践——新内容即新 URL,天然实现失效,配合 HTML 使用 no-cache 保证入口总是最新;而版本目录或同名覆盖则需显式 Purge。工程上应:HTML 用 no-cache 短缓存,静态资源用 hash 长缓存,发布时浏览器只重新拉 HTML,HTML 引用新 hash 的同名静态资源,CDN 无需 Purge 即可完成切换。

"失效"的本质是"让旧缓存不再被命中"。hash 文件名通过 URL 变更实现零成本与零延迟失效且原子(新版本不覆盖旧版本),是最优实践;Purge 是按 URL 同名失效,存在时间窗口与传播延迟。预热与失效结合,能在发布时既保证一致又避免回源雪崩。

#
★★★

9. HTML no-cache、JS/CSS immutable 长缓存的缓存分层

请说明 HTML 使用 no-cache 而 JS/CSS 使用 immutable 长缓存的缓存分层策略及原因?

  • 缓存分层的结构与原理
  • no-cache 与 no-store 的区分
  • HTML 作为"入口"的更新机制

该策略把缓存分成两层:HTML 是入口,用 Cache-Control: no-cache(意思是使用前必须重新验证,但可缓存),每次加载都向服务器重新验证,从而保证拿到最新版本;JS/CSS 等静态资源用内容 hash 命名,配合 Cache-Control: public, max-age=31536000, immutable 长缓存,几近永不变。当发布新版本时,HTML 更新并引用新的 hash 文件名,浏览器拿到新 HTML 后发现资源 URL 变了,重新下载新资源,旧资源继续留在缓存中但不再被引用(可被清理)。这样既保证入口最新,又最大化静态资源命中率。no-cache 不等于 no-store,no-store 是完全不缓存。

这是"入口新鲜、资源久存"的黄金分层。HTML 小且必须最新,故每次验证;静态资源大、内容随 URL 唯一,故长缓存。二者配合实现"发布即生效 + 资源复用",是工程性能的基础。

#
★★★

10. Cache API 在 Service Worker 之外的工程价值与现代浏览器限制

请说明 Cache API 在 Service Worker 之外的工程价值以及现代浏览器的能力限制?

  • Cache API 的可访问性(仅 SW 与 Window 一定上下文)
  • 在无 SW 场景的判断
  • 现代浏览器限制(Secure Context、配额、跨域隔离)

Cache API(caches.open())实际上并不仅限于 Service Worker,在 Window 上下文中(页面主线程)也可以访问,因此可在没有 SW 的页面中直接用来做资源缓存。但它的工程价值主要在 SW 场景:SW 生命周期较长、可离线拦截、可后台预缓存。现代浏览器限制包括:需要 Secure Context(HTTPS/localhost);存储有配额(受 Quota 管理,可能被清理);Cache API 的响应需合法(如不能跨域缓存 opaque 响应过多);在新版 Chrome 中引入的分区缓存(Cache Partitioning)会让第三方上下文的缓存与顶级站点隔离,影响跨站资源复用。因此 Cache API 的"额外价值"在于:无 SW 也能做简单缓存、用于预缓存、配合编程式缓存策略。

关键认知是"Cache API 不等于 SW 专属",但 SW 是发挥其离线/拦截价值的主场景。浏览器限制(Secure Context、配额、分区)决定了它不适合作为大容量永久存储,也不适合存敏感数据。

#
★★★

11. fetch/XMLHttpRequest/WebSocket/SSE/EventSource 在通信模型与重连策略的工程取舍

请对比 fetch、XMLHttpRequest、WebSocket、SSE(EventSource)在通信模型与重连策略上的工程取舍?

  • 各 API 的通信模型(请求-响应、全双工、单向推送)
  • 重连策略(fetch 无内建重连、SSE 自动重连、WebSocket 需手动心跳)
  • 适用场景选择

fetch 是 Promise 化的请求-响应模型,适合普通 HTTP 请求,需自行实现重试与超时;XMLHttpRequest 是旧式 AJAX 对象,支持进度事件与 abort,但 API 较繁琐,现代项目优先用 fetch。SSE(EventSource)是单向服务器推送,基于 HTTP 长连接,内建自动重连与 Last-Event-ID 断点续传,适合 AI 流式输出、通知、实时日志等单向流。WebSocket 是全双工双向通道,适合交互式双向实时通信(聊天、协作、游戏),但需自行实现心跳、重连与粘性会话。工程取舍:需要双向实时交互用 WebSocket;只需服务器单向推送用 SSE(更简单、可自动重连、走 HTTP/2 多路复用);普通请求用 fetch。SSE 在 HTTP/2 下可多路复用,成本低于 WebSocket。

核心是"通信模型匹配":请求-响应(fetch/XHR)、单向推送(SSE)、双向全双工(WebSocket)。SSE 因自动重连与 HTTP 兼容性更适合大部分"通知/流式"场景;WebSocket 在真正双向交互且需低延迟时胜出。重连策略上 SSE 内建、WebSocket 需自建。

#
★★★

12. ESI(Edge Side Includes)在边缘片段缓存的工程价值

请说明 ESI(Edge Side Includes)在边缘片段缓存的工程价值及其与 CDN 的关系?

  • ESI 工作原理(边缘标签包含)
  • 片段级缓存与整页缓存
  • 现代替代方案(HTML 流式、边缘函数)

ESI(Edge Side Includes)是一种让 CDN 边缘按标签把页面片段组合的技术。页面模板中写入 <esi:include src="/news/headline" />,边缘节点在返回响应时,被标记的片段可以单独缓存,边缘根据片段缓存拼接完整 HTML。这样"整页缓存"可拆成"片段缓存",动态片段的缓存策略可与静态片段不同,极大提升动态页面的命中率与性能。它的价值在于:整页动态化时仍能缓存静态骨架,动态片段单独回源。现代替代方案包括边缘函数(Cloudflare Workers/Fastly)动态拼接、HTML 流式渲染(streaming SSR)与 CDN 的 partial caching。ESI 已较少被主推,但其"片段缓存"思想仍是边缘缓存重要设计。

ESI 的核心是把"页面级缓存"拆细到"片段级缓存",让动态与静态内容共存同一页面。虽然 ESI 自身生态式微,但它的设计思想(边缘组装、片段缓存)被边缘函数与流式 SSR 继承。

#
★★★

13. Cloudflare CDN 与 Fastly/KeyCDN 在灰度发布与回源的工程取舍

请对比 Cloudflare、Fastly、KeyCDN 等 CDN 在灰度发布与回源机制上的工程取舍?

  • 各 CDN 的缓存与回源配置差异
  • 灰度发布(分比例、分地域、分头部分流)
  • 边缘规则与自定义逻辑

Cloudflare 提供 Workers 与丰富的边缘规则,支持基于 Cookie、Header、URL 的灰度分流,可精确控制流量比例与回源配置,回源需配置 Origin 或 Terraform 管理;Fastly 以 VCL(Varnish Configuration Language)为特色,支持极细粒度的缓存、回源与请求改写,且缓存失效极快(Purge 秒级),适合对缓存控制要求高的场景;KeyCDN 定位于简单、价格友好,提供基础缓存与 Geo 规则,灰度能力较弱。取舍上:需要复杂灰度与边缘逻辑选 Cloudflare/Fastly;需极致缓存控制与秒级失效选 Fastly;追求简单低成本选 KeyCDN。回源都需考虑源站健康检查、超时与回源失败降级。

灰度发布的核心是"按条件把流量分发到不同版本",CDN 边缘规则是实现的关键。Cloudflare/Fastly 因边缘可编程能力更强而适合灰度;KeyCDN 偏基础。回源则需兼顾源站稳定性与 CDN 的集中到源策略。

#
★★★

14. Vary 头部在多语言/多设备响应的工程价值

请说明 Vary 响应头在多语言、多设备响应中的工程价值及其与缓存键的关系?

  • Vary 头的语义(按请求头区分缓存)
  • 多语言(Accept-Language)与多设备(User-Agent)场景
  • Vary 与缓存键、缓存碎片化

Vary 响应头告诉 CDN/浏览器缓存"这个 URL 的响应因某些请求头不同而不同",缓存时应把这些请求头纳入缓存键。例如 Vary: Accept-Language 表示同一 URL 不同语言返回不同内容,CDN 需按语言分别缓存;Vary: User-Agent 表示桌面/移动端内容不同。没有 Vary 会导致 CDN 把某种语言/设备的响应错误地返回给其他请求,造成内容错乱。但 Vary 的代价是缓存碎片化:有多少种请求头值就有多少份缓存,命中率下降。工程上应尽量把多语言/多设备放到 URL 路径而非依赖 Vary(如 /zh-cn/、/m/),以减少缓存碎片化;确需 Vary 时需兼顾缓存命中率。

Vary 是"内容协商"与缓存的桥梁。它让缓存区分同一 URL 下的不同表现,代价是碎片化。工程取舍是在"正确的多表现缓存"与"缓存命中率"之间权衡,倾向用 URL 区分而非 Vary。

#
★★★

15. 多级缓存(浏览器、CDN、边缘、源站)的协作

请说明浏览器、CDN、边缘、源站多级缓存的协作机制与命中流程?

  • 缓存层级结构与各层职责
  • 命中流程(浏览器→CDN→边缘→源站)
  • 各层缓存头控制与失效

多级缓存形成从用户到源站的层级:浏览器缓存(local/disk cache,受 Cache-Control 控制)→ CDN 边缘节点缓存(共享缓存,受 s-maxage/CDN-Cache-Control 控制)→ 边缘计算层(Workers/Edge Functions,可编程缓存)→ 源站(应用/数据库缓存,如 Redis)。请求命中流程是逐级向上:浏览器缓存命中不再发网络请求;未命中则向 CDN 边缘请求,CDN 命中直接返回;未命中则回源,源站可自身命中应用缓存。各级缓存需协调各自的 TTL 与失效策略,避免"上级缓存陈旧导致下级无法更新"。工程上通常用 HTML 短缓存 + 静态资源 hash 长缓存来让各层精确协作,边缘层负责动态内容的缓存与降级。

多级缓存是"逐级就近命中、逐级向上回源"的漏斗。层级越多越接近用户、延迟越低,但一致性管理越复杂。关键是把缓存策略按层级正确配置(s-maxage 控制共享层,max-age 控制浏览器层),并让入口层(HTML)保证新鲜。

#
★★★

16. Cookie 的 SameSite、HttpOnly、Secure 在安全与缓存的工程取舍

请说明 Cookie 的 SameSite、HttpOnly、Secure 属性在安全与缓存场景下的工程取舍?

  • SameSite(Strict/Lax/None)的 CSRF 防护与第三方嵌入
  • HttpOnly 防 XSS 读取
  • Secure 保证仅 HTTPS 传输

SameSite 控制 Cookie 是否随跨站请求发送:Strict 完全不随跨站请求发送,Lax 允许顶级导航 GET 携带,None 允许跨站但需 Secure 且无 SameSite 防护。设置 SameSite=Lax 是默认且能防大多数 CSRF。HttpOnly 防止脚本 document.cookie 读取,阻断 XSS 窃取会话。Secure 确保 Cookie 仅经 HTTPS 传输,防止中间人截获。在缓存方面,含 Cookie 的个性化响应不应被 CDN 共享缓存缓存(否则会泄露给其他用户),应设置 Cache-Control: no-store 或用 Vary: Cookie(但碎片化)。工程取舍:登录态 Cookie 用 HttpOnly+Secure+SameSite=Lax,并向第三方嵌入场景拓展时用 None。安全 Cookie 通常配合 no-store 保证不被缓存。

SameSite 是 CSRF 的第一道防线、HttpOnly 防 XSS 窃取、Secure 防传输泄露,三者叠加形成纵深防御。缓存上,带 Cookie 的个性化响应必须排除共享缓存,否则跨用户串数据。

// 设置安全 Cookie
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400
#
★★★

17. HTTP/3(QUIC,基于 UDP)在多路复用与连接迁移的工程价值

请说明 HTTP/3(基于 QUIC/UDP)在多路复用与连接迁移方面的工程价值?

  • QUIC 基于 UDP 与 0-RTT/1-RTT 握手
  • 多路复用且无队头阻塞
  • 连接迁移(Connection Migration)与网络切换

HTTP/3 使用 QUIC 协议,QUIC 基于 UDP 并在用户态实现可靠传输、加密与多路复用。相比 HTTP/2(基于 TCP),QUIC 解决了 TCP 层面的队头阻塞(一个 TCP 分片丢失会阻塞所有流),每条流独立交付,某条流的丢包不会阻塞其他流。QUIC 的连接迁移(Connection Migration)允许连接使用连接 ID(Connection ID)而非 IP:端口标识,Wi-Fi 与蜂窝网络切换时连接不中断,对移动端体验重要。QUIC 结合 TLS 1.3 提供 0-RTT/1-RTT 握手,减少建连延迟。工程价值:移动网络下更稳、更快;多路复用无队头阻塞;连接迁移让弱网切换更平滑。代价是 UDP 在一些传统代理/防火墙环境下可能被拦截,需回退 HTTP/2。

HTTP/3 的核心价值是把"传输层优化"与"应用层多路复用"结合。连接迁移是杀手级特性,靠连接 ID 而非 4 元组标识,让 IP 变化不重建连接。无队头阻塞则来自基于流的独立交付。

#
★★★

18. 从 URL 输入到首帧显示的导航阶段(DNS、TCP、TLS、HTTP、解析、渲染)

请描述从 URL 输入到首帧显示的完整导航阶段?

  • DNS 解析、TCP 握手、TLS 握手、HTTP 请求
  • HTML 解析、CSS 计算、JS 执行、布局、绘制
  • 关键性能指标(TTFB、FCP、LCP)

完整流程为:1) URL 输入与解析(协议、域名、路径);2) DNS 解析域名得到 IP(可命中缓存/预加载);3) 建立 TCP 连接(三次握手);4) 若是 HTTPS,进行 TLS 握手(协商密钥);5) 发送 HTTP 请求,服务端响应(TTFB 起点);6) 浏览器接收 HTML 并解析构建 DOM 树;7) 解析 CSS 构建 CSSOM;8) 执行 JavaScript(可能阻塞解析);9) 布局(Layout)计算几何;10) 绘制(Paint)与合成(Composite),首帧显示。HTML 解析过程中遇到外部资源会触发预加载扫描器(preload scanner)提前发现并下载关键资源。性能上,导航时间(TTFB)由网络与服务器决定,FCP 与 LCP 由资源加载与渲染决定。

该流程是前端性能优化的基础。网络阶段(DNS/TCP/TLS/HTTP)决定 TTFB,解析与渲染阶段决定 FCP/LCP。优化点分布在每个阶段:DNS prefetch、HTTP/2/3、preload、关键 CSS/JS 内联、减少阻塞等。

#
★★★

19. HTTP/3 的 0-RTT 握手与重放风险的应用边界

请说明 HTTP/3 的 0-RTT 握手及其重放风险的应用边界?

  • 0-RTT 意义(首包即送数据)
  • 重放攻击风险(0-RTT 数据可能被重放)
  • 应用边界与规避(幂等请求、限制 0-RTT 数据)

0-RTT 是 QUIC 在已建立过连接(缓存了会话密钥)时,客户端可在第一个数据包中直接携带 HTTP 请求数据,无需等待握手往返,从而节省一个 RTT。但 0-RTT 数据存在重放风险:攻击者可能截获并重放 0-RTT 请求,因服务端还未完成握手,无法区分重放。因此 0-RTT 只适合对幂等、无副作用、可容忍重复的请求(如 GET、静态资源),且服务端应限制 0-RTT 数据量、对关键操作禁止 0-RTT。应用边界:0-RTT 用于提升首屏与资源加载性能,但登录、支付等非幂等操作必须走完整 1-RTT,或服务端用 anti-replay 机制(如 nonce、TLS 1.3 的 early_data 需校验)。

0-RTT 是"性能"与"安全"的权衡。其价值是省一个 RTT,风险是重放。安全边界是:仅对幂等请求启用 0-RTT,服务端需配套 anti-replay(如 QUIC 的地址验证、nonce),并限制 early data 大小。

#
★★★

20. 预加载扫描器(Preload Scanner)对关键资源发现的影响

请说明预加载扫描器(Preload Scanner)对关键资源发现的影响?

  • 预加载扫描器的工作原理
  • 提前发现资源与阻塞解析的关系
  • 与 preload 提示的配合

预加载扫描器(Preload Scanner)是浏览器在 HTML 解析器遇到阻塞(如同步脚本执行)时,并行扫描后续 HTML,提前发现图片、样式、脚本、字体等资源并开始下载,从而无需等待解析器推进。它把"解析阻塞"与"资源发现"解耦,显著提升关键资源加载速度。影响:让关键资源(CSS、首屏图片、字体)在解析阻塞期间就被提前下载,缩短 LCP;与 preload 提示配合,可进一步精确控制关键资源的发现与下载时机。工程价值:只要 HTML 中能静态声明资源,预加载扫描器就能提前拉起,开发者无需手动优化大多数后置资源。

预加载扫描器是浏览器针对"解析阻塞"的优化,它并行扫描提前发现资源,避免等待解析器。它是浏览器默认能力,preload 是显式补充。工程上应让关键资源可被扫描器发现(静态引用),并配合 preload 处理动态/后置资源。

#
★★★

21. Service Worker 与导航的协作(fetch 事件、Navigation Preload)

请说明 Service Worker 与导航的协作,包括 fetch 事件与 Navigation Preload 的作用?

  • SW 拦截导航请求的 fetch 事件
  • Navigation Preload 的意义(并行网络请求)
  • 与 HTTP 缓存、Predictive 的配合

导航请求(页面主文档)也会被 Service Worker 的 fetch 事件拦截,SW 可以决定返回缓存、走网络或两者结合。Navigation Preload(导航预加载)允许 SW 在调用 fetch 处理导航的同时,并行发起网络请求预取主文档,从而避免"SW 先查缓存、再发网络请求"的串行延迟。SW 通过 event.preloadResponse 获取预加载结果,与缓存命中结果做竞速或 fallback。这解决了 SW 过慢的问题:SW 启动与逻辑执行不必阻塞网络请求。工程上,SPA 的 App Shell 可用缓存,HTML 内容用 navigation preload 网络请求,达到"秒开 + 新鲜"。

核心是 NAV 预加载让"SW 处理"与"网络请求"并行,消除 SW 引入的额外延迟。SW 拦截导航既要保证离线体验,又不能拖慢在线导航,preload 是关键加速手段。

self.addEventListener('activate', (e) => {
  e.waitUntil(self.registration.navigationPreload.enable());
});
self.addEventListener('fetch', (e) => {
  if (e.request.mode === 'navigate') {
    e.respondWith((async () => {
      const cache = await caches.match(e.request);
      const preload = e.preloadResponse; // 并行网络请求
      const network = preload || fetch(e.request);
      return cache || network;
    })());
  }
});
#
★★★

22. 导航中的 HTTP/2 优先级与依赖提示对关键资源加载顺序的影响

请说明 HTTP/2 的优先级与依赖提示对导航中关键资源加载顺序的影响?

  • HTTP/2 流优先级(依赖与权重)
  • 浏览器对资源优先级的默认分配
  • 与 preload 的配合与副作用

HTTP/2 引入流优先级机制,允许通过依赖(dependencies)与权重(weight)声明资源加载的相对顺序。浏览器会给关键资源分配默认优先级:HTML、CSS、字体更高,图片、脚本按阻塞情况。但 HTTP/2 优先级只是建议,服务端与 CDN 不一定严格执行,且现代浏览器对 HTTP/2 优先级的支持经历过反复(曾因优先级执行力不足而劣化)。关键资源(如 LCP 图片、首屏 CSS)应通过 <link rel="preload"> + as 显式提示,让浏览器尽早、高优先级下载。依赖提示(如 preload 的 fetchpriority)可进一步调整优先级。副作用:过度 preload 会抢占带宽,导致关键资源反而变慢,需适度。

HTTP/2 优先级是"建议性"的,不可完全依赖;preload 与 fetchpriority 是更可控的显式提示。工程上优先用 preload 精确控制关键资源,而非依赖优先级默认值。

#
★★★

23. HPACK/QPACK 头部压缩与多路复用

请说明 HPACK(HTTP/2)与 QPACK(HTTP/3)头部压缩的原理及其与多路复用配合的必要性?

  • HPACK 基于静态表/动态表/哈夫曼的头部压缩
  • QPACK 的流式编码与解耦(避免队头阻塞)
  • 压缩与多路复用的关系

HTTP/1.1 每次请求重复发送完整头,开销大。HTTP/2 的 HPACK 通过静态表(索引通用头部)、动态表(维护已发送头的索引)与哈夫曼编码压缩头部,大幅减少重复头。但 HTTP/2 中动态表的状态更新依赖先前帧,若某帧丢失会阻塞后续解压,造成队头阻塞。HTTP/3 的 QPACK 通过"编码器流"与"解码器流"把动态表状态管理与数据流解耦,数据流可独立交付,避免头部压缩导致的队头阻塞。多路复用(一条连接多条流)要求头部压缩与流解耦,否则一条流的头部问题会拖累整条连接。HPACK/QPACK 让多路复用下头部开销显著降低。

头部压缩是让多路复用真正高效的前提。HPACK 用静态+动态表压缩;QPACK 用专用流解耦状态,适配 QUIC 的无队头阻塞特性。两者都减少带宽与延迟,但实现复杂度不同。

#
★★★

24. 队头阻塞(HOL)在 HTTP/1.1、HTTP/2、HTTP/3 的演进

请说明队头阻塞(Head-of-Line Blocking)在 HTTP/1.1、HTTP/2、HTTP/3 中的演进与解决方式?

  • HTTP/1.1 的 HTTP 层队头阻塞(Pipelining 失败)
  • HTTP/2 解决 HTTP 层 HOL 但仍有 TCP 层 HOL
  • HTTP/3 基于 QUIC 解决 TCP 层 HOL

HTTP/1.1 的队头阻塞体现在协议层:同一连接上 Pipelining 时前一个请求必须响应后才能处理下一个,因不支持乱序响应,导致阻塞;浏览器用多连接(6 个)缓解。HTTP/2 通过多路复用(一条连接多个流,流可乱序交付)解决了 HTTP 层队头阻塞。但 HTTP/2 基于 TCP,TCP 层仍存在队头阻塞:一个 TCP 分片丢失会导致该连接上所有流被阻塞等待重传。HTTP/3 基于 QUIC(UDP),每条流独立交付,一条流的丢包只影响该流,彻底解决 TCP 层队头阻塞。因此演进是:HTTP/1.1 协议层 HOL → HTTP/2 解决协议层但残留 TCP 层 HOL → HTTP/3 解决传输层 HOL。

队头阻塞的演进本质是"多路复用下沉到传输层"。HTTP/2 在应用层复用但受 TCP 单字节流限制;HTTP/3 把可靠性下沉到 QUIC 的流级别,实现真正无干扰的多路复用。

#
★★★

25. HTTP/1.1、HTTP/2、HTTP/3 的连接模型差异

请对比 HTTP/1.1、HTTP/2、HTTP/3 的连接模型差异?

  • 连接数量(多连接 vs 单连接多路复用)
  • 传输层(TCP vs UDP/QUIC)
  • 头部压缩与握手

HTTP/1.1:每个连接只能串行处理一个请求(Pipelining 基本不可用),浏览器通常对一个域名建立 6 个连接以提升并发,传输层 TCP,无头部压缩,存在队头阻塞。HTTP/2:一条 TCP 连接(通常与1.1同样的连接数,但可多路复用)承载多个并发流,支持头部压缩(HPACK)、流优先级、服务器推送(已弃用),解决协议层队头阻塞,但仍有 TCP 层队头阻塞。HTTP/3:基于 UDP 的 QUIC,一条连接可多路复用且无队头阻塞,支持连接迁移、0-RTT,头部压缩用 QPACK。连接模型差异核心:连接数(1.1 多连接、2/3 单连接多路复用)、传输层(TCP vs UDP)、是否无队头阻塞。

HTTP/2 与 HTTP/3 都倾向"单连接多路复用"以减少连接与握手开销,区别在传输层。HTTP/3 用 QUIC 把多路复用与可靠性下沉到传输层,解决 TCP 层队头阻塞并支持连接迁移。

#
★★★

26. SSE 的自动重连与 Last-Event-ID 与 HTTP/2/HTTP/3 的取舍

请说明 SSE 的自动重连与 Last-Event-ID 机制及其与 HTTP/2、HTTP/3 的取舍?

  • EventSource 自动重连与 Last-Event-ID 断点续传
  • SSE 在 HTTP/2/HTTP/3 下的多路复用与资源占用
  • SSE 与 WebSocket 的取舍

SSE(EventSource)基于 HTTP,内建自动重连:连接断开时浏览器自动重连,且可通过 Last-Event-ID 请求头把上次收到的最后事件 ID 发给服务器,服务器据此续传,实现断点续传。它在 HTTP/2 下可与同域其他请求多路复用,连接成本低,且是单向推送的天然选择。在 HTTP/3 下可复用 QUIC 连接。取舍:SSE 适合单向流(AI 流式输出、通知、日志),自动重连是优势;WebSocket 适合双向交互。SSE 的局限是单向、浏览器对连接数限制(HTTP/1.1 下每域 6 条)、某些代理可能缓冲导致流式不及时(需禁用缓冲)。对 AI 流式响应,SSE 是主流方案。

SSE 的核心优势是"内建重连 + Last-Event-ID 续传 + HTTP 兼容性",无需自建心跳。在 HTTP/2/3 下多路复用大幅降低连接成本,使其成为单向推送的优选。限制是单向性与代理缓冲。

const es = new EventSource('/api/stream');
es.onmessage = (e) => console.log(e.data);
// 服务端响应头 + 事件
// Content-Type: text/event-stream
// id: 42\n data: hello\n\n
#
★★★

27. DNS over HTTPS 与 Early Hints(103)

请说明 DNS over HTTPS(DoH)与 HTTP Early Hints(103)的用途与工程价值?

  • DoH 加密 DNS 查询防窃听/篡改
  • Early Hints(103)在握手中提前返回 preload 链接
  • 对 TTFB 与 LCP 的优化

DNS over HTTPS(DoH)把 DNS 查询封装在 HTTPS 中,防止 DNS 被中间人窃听或篡改,提升隐私与安全(如 China 的 DNS 污染场景)。浏览器(Chrome 等)默认在系统 DNS 与 DoH 间选择。HTTP Early Hints(103)允许服务器在最终响应之前先发送 103 状态码,其中携带 <link rel="preload"> 提示,让浏览器在 TTFB 未到时就提前下载关键资源(如 CSS、LCP 图片),从而缩短 LCP。工程价值:DoH 提升域名解析安全与稳定性;Early Hints 在服务器处理慢时也能提前启动资源加载,尤其适合 SSR 慢接口。两者结合可显著降低首屏延迟。

DoH 解决"DNS 查询本身不安全"的问题;Early Hints 解决"服务器处理时间导致资源加载推迟"的问题,通过提前 push 预加载提示。都是降低关键路径延迟的补充手段。

#
★★★

28. WebTransport 的双向流 + datagram 在大型应用的网络性能工程价值

请说明 WebTransport 的双向流与 datagram 在大型应用的网络性能工程价值?

  • WebTransport 基于 HTTP/3(QUIC)的双向流与 datagram
  • 无序可靠性(datagram)与有序可靠(流)的选择
  • 相对 WebSocket 的性能优势

WebTransport 是基于 HTTP/3(QUIC)的新 API,提供双向的、低延迟的传输能力。它支持两类数据通道:Streams(有序、可靠、类似 HTTP/2 流)与 Datagrams(无序、不可靠、但低延迟,类似 UDP)。这允许应用在"需要可靠有序"(如文件、状态同步)与"需要低延迟容忍丢包"(如实时游戏坐标、音视频、遥测)之间灵活选择。工程价值:相比 WebSocket,WebTransport 无队头阻塞、支持真多路复用与消息乱序、连接迁移、0-RTT 握手,适合大规模实时协作、游戏、直播、IoT 等。限制是浏览器支持尚不全面(需 HTTP/3 + 安全上下文)。

WebTransport 的价值在于"把 QUIC 的流与 datagram 能力暴露给 Web",让应用层自定义可靠性/延迟模型。选择流(可靠有序)还是 datagram(低延迟无序)是核心设计决策。

#
★★

29. DNS Prefetch / preconnect/dns-prefetch 与 HTTP/2 连接复用的工程价值

请说明 dns-prefetch、preconnect 与 HTTP/2 连接复用对性能的工程价值与取舍?

  • dns-prefetch 与 preconnect 的差异
  • 关键三方域名(图片 CDN、字体、API)的优化
  • HTTP/2 连接复用与 preconnect 的关系

dns-prefetch 提前解析目标域名的 DNS(<link rel="dns-prefetch" href="//cdn.example.com">),省去导航时的 DNS 查询时间;preconnect 更进一步,提前建立 TCP+TLS 连接(<link rel="preconnect">),甚至可配合 HTTP/2 连接复用,让后续请求直接复用已建连接。对关键三方域名(图片 CDN、字体服务、第三方 API)很有价值。取舍:preconnect 会占用连接资源,不适合同一页面多处大量使用;dns-prefetch 成本低、适合大量域名。工程上:对最重要的 1-3 个域名用 preconnect,对次要域名用 dns-prefetch。HTTP/2 连接复用让 preconnect 建立的一条连接被多个请求共享,放大其收益。

dns-prefetch 只做 DNS 预解析,preconnect 含建连(更重)。回退是 preconnect 自带 dns-prefetch(浏览器自动降级)。关键是要"适可而止",只对真正关键域名使用,避免浪费。

#
★★

30. HTTP 103 Early Hints 与 preload 在 TTFB 与 LCP 的工程价值

请说明 HTTP 103 Early Hints 与 preload 在改善 TTFB 与 LCP 方面的工程价值?

  • 103 Early Hints 提前推送 preload 链接
  • preload 对关键资源的提前下载
  • 对 TTFB 与 LCP 的影响

103 Early Hints 让服务器在生成最终响应前,先发送 103 头,其中包含 <link rel="preload"> 提示,浏览器立刻开始下载这些关键资源,而无需等待完整响应(TTFB)。这针对"服务器处理慢"的场景:即使 HTML 生成慢,浏览器也能提前并行下载 CSS、字体、LCP 图片。preload 本身是显式声明提前加载的资源,与 Early Hints 结合,把"资源发现"提前到服务器处理之前。工程价值:减少关键资源的等待时间,从而缩短 LCP;对 SSR 慢接口、动态页面尤其有效。限制:需 CDN/服务器支持 103,且 preload 要精确,避免下载无用资源。

Early Hints 把"浏览器等 HTML"与"浏览器下载关键资源"并行化,本质是去掉"发现资源"的等待。preload 是发现手段,Early Hints 是传输时机。二者配合直接优化 LCP。

#
★★

31. HTTP Range Request 在视频与大型资源下载的应用

请说明 HTTP Range Request(范围请求)在视频与大型资源下载中的应用?

  • Range 请求头与 206 Partial Content 响应
  • 断点续传、视频拖动、分片下载
  • 服务端支持(Accept-Ranges)

HTTP Range 请求通过 Range: bytes=start-end 请求特定字节范围,服务端返回 206 Partial ContentContent-Range 头,只发送该范围数据。这主要用于:视频播放(拖动进度条时可跳过已缓冲部分,只请求所需片段)、断点续传(下载中断后从上次位置继续)、大文件分片并行下载。服务端需支持 Range,通过 Accept-Ranges: bytes 响应头声明。工程上,视频播放器利用 Range 实现按需加载与 seek;CDN 对 Range 请求做分段缓存。无 Range 支持时浏览器会重新下载整个文件,浪费带宽。

Range 请求把"全量下载"拆成"按需分片",是流媒体与断点续传的基础。核心是只传输必要字节,配合 CDN 分片缓存与字节范围缓存,提升大资源体验。

#
★★

32. HTTP 方法语义(GET 安全幂等、POST/PATCH 边界)

请说明 HTTP 方法语义,特别是 GET 安全幂等、POST 与 PATCH 的边界?

  • 安全方法(GET/HEAD/OPTIONS)与幂等方法(GET/PUT/DELETE)
  • POST 非幂等、PATCH 部分更新
  • 语义正确性对缓存与重试的影响

安全方法(safe)指不会改变服务器状态的方法:GET、HEAD、OPTIONS。幂等方法(idempotent)指重复执行结果相同:GET、PUT、DELETE、HEAD。POST 既非安全也非幂等,用于创建资源;PATCH 用于部分更新,语义上非幂等(虽然实现上可幂等)。语义正确性影响工程行为:GET 应被缓存、可被预加载/重试;POST 不能被缓存、不能自动重试(可能重复创建);PUT/DELETE 可安全重试。工程上应严格遵循语义,避免用 GET 做有副作用的操作(会被缓存/CDN 污染、被爬虫触发),避免用 POST 做可安全重试的原子操作。

方法语义是 HTTP 协议自描述的契约。安全与幂等属性决定缓存、重试、预加载的合法性。正确方法选择是 RESTful 设计的基础,也影响下游缓存与容错。

#
★★

33. HTTP/2 的 Server Push(已弃用)与替代 在大型前端项目的工程价值

请说明 HTTP/2 Server Push 为何被弃用以及其替代方案在大型前端项目的工程价值?

  • Server Push 的缺点(推送无法撤回、缓存无法感知、带宽浪费)
  • 替代方案:103 Early Hints、preload、普通请求
  • 大型项目的选择

HTTP/2 Server Push 允许服务器主动推送资源,但存在严重问题:服务器无法知道浏览器是否已缓存该资源,会重复推送;推送无法撤回,可能浪费带宽;与浏览器缓存、preload 冲突,难以控制。因这些问题,Chrome 已弃用 Server Push,主流浏览器不再支持,推荐用 103 Early Hints 配合 preload 替代。Early Hints 让浏览器主动请求,浏览器能感知缓存、精确控制,避免重复推送。大型项目工程价值:用 preload + Early Hints 精确控制关键资源加载,资源由浏览器按需请求,配合缓存命中,避免带宽浪费。Server Push 已不应再使用。

Server Push 的致命伤是"服务器盲目推送、无法感知缓存"。替代方案(Early Hints + preload)把"决定权"交还浏览器,更符合缓存与带宽控制。大型项目应弃用 Server Push。

#
★★

34. WebSocket 在大型应用的网络性能工程价值

请说明 WebSocket 在大型应用中的网络性能工程价值及其代价?

  • 全双工低延迟双向通信
  • 连接复用与心跳
  • 代价:连接常驻、集群/负载均衡、粘性会话

WebSocket 提供全双工双向通道,一次握手后持续通信,避免频繁 HTTP 握手开销,适合实时交互(聊天、协作、实时行情、游戏)。工程价值:低延迟、双向推送、连接复用。代价与限制:连接是长连接,占用服务器资源;HTTP 层无法缓存;需要心跳保活(处理 NAT 超时、代理断开);跨中间代理需正确配置 Upgrade;负载均衡下需粘性会话(sticky session)或统一消息总线;连接数多时需扩容与水平扩展(依赖 Redis 等消息广播)。大型应用需权衡:连接数、扩容、断线重连、心跳与安全。对"通知/单向推送"场景,SSE 可能更轻量。

WebSocket 的价值在真正双向实时交互,代价是长连接资源与运维复杂度。大型应用需设计连接管理、心跳、重连与水平扩展,避免连接数成为瓶颈。

#
★★

35. fetch.keepalive 与单次请求后端连接复用的工程价值

请说明 fetch 的 keepalive 选项与浏览器连接复用(keep-alive/HTTP/2)的工程价值?

  • fetch keepalive 用于页面卸载时发送请求
  • 连接复用(keep-alive、HTTP/2 多路复用)减少握手
  • 使用场景(埋点、卸载上报)

fetch 的 keepalive: true 允许请求在页面卸载(unload/visibilitychange)后继续发送,用于可靠的埋点上报、离开时保存状态,避免因页面销毁而请求被终止。它不阻塞页面卸载,且请求体积默认限制(64KB)。与之相关的"连接复用"(keep-alive/HTTP 持久连接、HTTP/2 多路复用)是让多个请求复用同一 TCP 连接,减少握手与往返。工程价值:keepalive 保证关键上报不丢失;连接复用降低网络开销。二者都提升网络效率与可靠性。注意 keepalive 请求不能过大,且不适合长任务。

两个概念不同:fetch keepalive 解决"卸载时请求被取消",连接复用解决"多个请求共用连接"。工程上埋点上报多用 keepalive,页面内众多请求靠连接复用降本。

navigator.sendBeacon('/trace', payload); // 或
fetch('/trace', { method: 'POST', keepalive: true, body: payload });
#
★★

36. AbortController 在 fetch 链路取消的工程价值(含上传进度)

请说明 AbortController 在 fetch 链路取消中的工程价值,包括上传进度场景?

  • AbortController/AbortSignal 取消 fetch
  • 取消上传与下载、进度控制
  • 超时与竞态处理

AbortController 提供 signal 传给 fetch,通过 controller.abort() 取消请求,浏览器会终止网络请求并触发 AbortError。工程价值:取消过期请求(搜索输入变化时)、组件卸载时取消,避免状态更新与竞态;实现超时(setTimeout(() => controller.abort()));配合上传进度,可在取消时中断上传并释放资源。上传进度可用 XMLHttpRequest.upload.onprogress 或 fetch 的 ReadableStream 追踪。AbortSignal 可组合(AbortSignal.any())合并多个取消源。陷阱:abort 后需 catch 区分 AbortError 与真实错误,避免误报。

AbortController 是把"取消"纳入 fetch 的标准机制。它解决过期响应、竞态、内存泄漏与资源释放。工程上需配合 catch 区分 AbortError,正确清理。

const controller = new AbortController();
fetch('/upload', { method: 'POST', body, signal: controller.signal })
  .catch(e => { if (e.name !== 'AbortError') throw e; });
// 取消
controller.abort();
#
★★

37. HTTP/2 的连接复用(Connection Reuse)

请说明 HTTP/2 的连接复用(Connection Reuse)机制及其工程价值?

  • 单连接多路复用
  • 连接复用的条件(同域、协商)
  • 减少握手与连接开销

HTTP/2 在一条 TCP 连接上通过多路复用承载多个并发请求/响应,连接复用指同一域名(或允许的跨域)的多次请求复用同一条连接。这减少了建立多条 TCP 连接与 TLS 握手的开销,提高连接利用率。连接的复用受协商影响(HTTP/2 通过 ALPN 协商),且浏览器对同一域名的连接可复用。工程价值:降低握手成本、减少慢启动、提升吞吐;缺点是单连接若遇到 TCP 层队头阻塞会影响所有流。跨域连接复用需相关服务端支持(如多域名共享连接)。HTTP/2 连接复用显著减少连接数。

连接复用的核心是"一条连接多处复用",把握手与连接建立成本摊薄到多个请求。相比 HTTP/1.1 的多连接,HTTP/2 单连接多路复用更省资源。需注意 TCP 层队头阻塞的残留。

#
★★

38. HTTP 状态码在 RESTful API 的正确使用

请说明 HTTP 状态码在 RESTful API 中的正确使用?

  • 2xx 成功、3xx 重定向、4xx 客户端错误、5xx 服务端错误
  • 常见状态码语义(200/201/204/400/401/403/404/409/422/429/500/502/503)
  • 语义正确性对客户端处理的影响

HTTP 状态码应精确表达结果:200 成功(GET),201 创建(POST),204 无内容;400 参数错误,401 未认证,403 无权限,404 不存在,409 冲突,422 语义校验失败,429 限流;500 服务端错误,502 网关错误,503 服务不可用,504 网关超时。正确使用状态码让客户端能准确判断并处理(401 触发刷新 token,403 提示无权限,429 触发退避,503 降级)。错误使用(如一律 200 带错误码)会增加客户端处理复杂度,丧失语义。工程上应区分客户端错误(4xx)与服务端错误(5xx),并配合错误体(Problem Details)提供详细信息。

状态码是 API 语义契约的一部分。正确分类让客户端能按语义自动化处理(重试、刷新、降级),滥用会破坏契约。RESTful 设计应精确选码。

#
★★

39. TLS 1.3 在大型前端项目的工程价值

请说明 TLS 1.3 在大型前端项目的工程价值?

  • TLS 1.3 的 1-RTT 握手与 0-RTT
  • 前向安全、移除旧算法
  • 对 HTTPS 性能与安全的影响

TLS 1.3 相比 1.2 大幅缩短握手:完整握手从 2-RTT 降为 1-RTT,支持 0-RTT(恢复会话时首包即带数据)。它移除了不安全算法(RC4、SHA-1、静态 RSA 密钥交换),强制前向安全(ECDHE),提升安全性。工程价值:HTTPS 建连更快(减少 TTFB),对移动弱网尤其明显;安全性更强。大型项目启用 TLS 1.3 需服务端配置,注意 0-RTT 的重放风险(仅用于幂等请求)。TLS 1.3 与 HTTP/2/3 协同,是安全与性能的基础。

TLS 1.3 的价值是"更快 + 更安全"。1-RTT 握手与 0-RTT 减少建连延迟,移除弱算法提高安全性。大型项目应全面启用并谨慎对待 0-RTT。

#
★★

40. HTTP 与传输层在跨端、跨平台、跨框架场景下的应用

请说明 HTTP 与传输层在跨端、跨平台、跨框架场景下的应用与挑战?

  • 跨端(Web/小程序/移动端/桌面)的 HTTP 差异
  • 传输层兼容(HTTP/2、HTTP/3、WebSocket)
  • 跨框架统一请求层

跨端、跨平台、跨框架场景下,HTTP 与传输层需统一抽象:各端(Web、小程序、React Native、Flutter、桌面)的请求能力不同(fetch/XHR/原生网络库),需封装统一请求层(拦截器、错误处理、重试、鉴权)。传输层需考虑兼容性:Web 支持 HTTP/2/3、WebSocket、SSE;小程序/原生端可能限制某些能力。跨框架(React/Vue)则把请求层抽离为框架无关模块。挑战:差异化的 cookie/存储、CORS/同源策略、TLS 证书、网络权限、代理。工程上,BFF(Backend-for-Frontend)统一协议与鉴权,客户端用统一 SDK 封装,屏蔽底层差异。

跨端场景的核心是"抽象统一、能力差异适配"。HTTP 语义在各端一致,但实现与限制不同,需用统一请求层 + BFF 屏蔽差异。传输层选择需考虑各端支持度。

#
★★

41. 缓存与 CDN 在客户端与边缘协同中涉及哪些源码关键路径与实现原理,应如何在性能与一致性之间取舍

请说明缓存与 CDN 在客户端与边缘协同中涉及的源码关键路径与实现原理,以及如何在性能与一致性之间取舍?

  • 缓存关键路径(请求、响应、命中、失效)
  • 客户端 SW 与边缘 CDN 的协同
  • 性能与一致性取舍

客户端与边缘缓存的协同涉及源码里的关键路径:请求发起(fetch 拦截)、响应读写(Cache API)、命中判定(cache.match)、失效与更新(SW 版本、CDN purge)。原理上,SW 可拦截请求决定从缓存或网络获取,CDN 边缘按响应头决定缓存时长。协同方式:SW 做离线与网络优先,CDN 做共享缓存与回源。性能与一致性取舍:长缓存(max-age=长、immutable)提升性能但更新慢;短缓存/no-cache 保一致但性能差。工程上分层:静态资源 hash 长缓存(性能)、HTML no-cache(一致)、API 按需 stale-while-revalidate(二者兼顾)。源码实现需在 SW 的 fetch 处理器与 CDN 配置中正确设置缓存键与策略。

协同的关键路径是"SW 拦截 + CDN 缓存 + HTTP 头"三层。取舍的核心是"内容变化频率"与"更新时效":变化越频繁越需短缓存,越稳定越可长缓存。用 hash 与分层策略兼顾性能与一致。

#
★★

42. Service Worker 在离线缓存与网络优先/缓存优先策略的现代应用

请说明 Service Worker 在离线缓存与网络优先/缓存优先策略中的现代应用?

  • 缓存优先(cache-first)与网络优先(network-first)策略
  • 离线支持与更新
  • 与备用策略(stale-while-revalidate)结合

Service Worker 通过缓存策略决定请求处理:缓存优先(cache-first)先查缓存命中即返回,未命中走网络并缓存,适合静态资源与 App Shell,离线表现好;网络优先(network-first)先请求网络,失败回退缓存,适合需常新的页面/API,保证在线时新鲜、离线时降级。stale-while-revalidate 返回缓存并后台更新。现代应用(PWA)通常组合:App Shell 用缓存优先,动态内容用网络优先或 SWR。离线时 SW 提供缓存内容,实现可用性。更新需管理 SW 版本与缓存清理,避免旧缓存堆积。

策略选择取决于"新鲜度 vs 离线可用性"。cache-first 离线好但陈旧,network-first 新鲜但依赖网络。SWR 在两者间平衡。现代应用混合使用并配合版本管理。

#
★★

43. CDN 边缘缓存(Cloudflare、Fastly、Vercel Edge)

请说明 Cloudflare、Fastly、Vercel Edge 等 CDN 边缘缓存的差异与工程选择?

  • 各平台边缘缓存模型
  • 缓存控制与失效
  • 与边缘计算/部署的集成

Cloudflare 提供全球边缘缓存 + Workers 边缘计算,缓存控制靠 Cache-Control 与 Cache API,Purge 快,适合通用 CDN 与边缘逻辑。Fastly 以 VCL 提供极细粒度缓存控制与秒级 Purge,适合缓存策略复杂、对失效时效要求高的场景。Vercel Edge 与 Vercel 部署深度集成,边缘缓存与边缘函数(Edge Functions)一体,适合 Vercel 生态的 Next.js 应用的 SSR/SSG 缓存。工程选择:已用 Vercel 部署选 Vercel Edge;需极致缓存控制选 Fastly;需通用 CDN + 边缘逻辑选 Cloudflare。边缘缓存都需正确设置缓存头与失效策略。

边缘缓存的核心差异在"控制粒度、失效速度、与部署/计算生态的集成"。选择取决于团队技术栈与缓存需求。三者都支持 s-maxage/Cache-Control 控制。

#
★★

44. CDN 缓存击穿、雪崩与穿透在前端 API 缓存的工程防护

请说明 CDN 缓存击穿、雪崩与穿透在前端 API 缓存中的工程防护?

  • 缓存击穿(热点过期)、雪崩(大面积过期)、穿透(查不到)
  • 前端 API 缓存场景
  • 防护策略(互斥锁、随机过期、空值缓存、兜底)

缓存击穿指某个热点 key 过期瞬间大量请求打到源站;雪崩指大量 key 同时过期导致源站压力激增;穿透指请求的 key 既不在缓存也不存在数据库,导致每次都打源站。前端 API 缓存场景同样存在:加锁(互斥/单飞,同一时间仅一个请求回源)、随机化过期时间(jitter 避免雪崩)、空值缓存(缓存不存在的响应,防穿透)、布隆过滤器(后端)、限流与兜底(stale-if-error 降级)。对 CDN 可配合 stale-while-revalidate 与预热。前端还可用请求去重(单飞)避免并发重复请求。

三种问题是"缓存失效导致的源站压力"。防护核心是"避免并发回源"(击穿用锁)、"避免同时过期"(雪崩用随机)、"避免空查"(穿透用空值缓存)。前端 API 层用请求去重与降级补齐。

#
★★

45. Service Worker 的 cache.match 与 fetch 的缓存策略工程实践

请说明 Service Worker 中 cache.match 与 fetch 的缓存策略工程实践?

  • cache.match 的匹配与缓存键
  • fetch 与缓存结合的策略
  • 请求方法、cache 模式(ignoreSearch)

在 SW 中,cache.match(request) 用于在缓存中按请求匹配响应,支持 options(如 ignoreSearch 忽略 query、ignoreVary)。fetch(request) 发起网络请求。策略实践是把两者组合:cache-first 先 match 再 fetch;network-first 先 fetch 失败再 match;SWR 返回 match 并后台 fetch 更新。需注意 cache.match 对 POST 请求通常不匹配(缓存只存 GET),且请求凭据(credentials)会影响匹配。工程上需统一缓存键(如规范化 URL),处理 opaque 响应(mode:'no-cors' 的缓存可能返回 undefined 状态)。策略要在 fetch 处理器中正确实现并处理 clone 与更新。

cache.match 与 fetch 是两个基元,策略即它们的组合。关键在于"命中判定、更新时机、key 规范化"。工程实践上把策略封装成函数,避免重复代码。

async function cacheFirst(req) {
  const cached = await caches.match(req, { ignoreSearch: true });
  if (cached) return cached;
  const res = await fetch(req);
  const copy = res.clone();
  caches.open('v1').then(c => c.put(req, copy));
  return res;
}
#
★★

46. Cache Partitioning(分区缓存)在第三方资源的浏览器缓存隔离

请说明 Cache Partitioning(分区缓存)对第三方资源的浏览器缓存隔离?

  • Cache Partitioning 的原理(按顶级站点分区)
  • 对第三方资源缓存的影响
  • 隐私与缓存命中率的权衡

浏览器缓存分区(Cache Partitioning)把缓存按"顶级站点 + 资源请求方"组合分区,即同一第三方资源在不同顶级站点下缓存彼此隔离,不再全局共享。目的是防止跨站通过缓存命中状态追踪用户(隐私)。影响:第三方资源(如 CDN 上的 JS、图片、字体)在访问不同站点时重新下载,缓存命中率下降、带宽增加,但这些资源通常体积可控。工程上,对共享第三方资源需接受分区带来的额外下载,或自行处理(如用 Service Worker、Service Worker 缓存是否分区因浏览器而异)。Chrome 已默认启用分区缓存。

分区缓存是隐私保护(防跨站缓存侧信道追踪)对缓存性能的牺牲。第三方资源缓存命中率下降是隐私红利支付的代价,工程上需权衡并从自建缓存/边缘缓存弥补。

#
★★

47. Preload 与 Prefetch( )的工程差异

请说明 preload 与 prefetch 的工程差异?

  • preload 提前加载当前页关键资源
  • prefetch 预取未来页面资源
  • 优先级与适用场景

<link rel="preload"> 用于提前加载当前导航关键资源(CSS、字体、LCP 图片),优先级高,浏览器会立即下载;<link rel="prefetch"> 用于预取未来可能访问的资源(如下一个页面的脚本),优先级低,浏览器空闲时下载。两者都需 as 属性声明资源类型。preload 用于当前页关键路径优化,prefetch 用于缓存预取(导航预测)。差异:优先级(preload 高、prefetch 低)、时机(preload 立即、prefetch 空闲)、用途(当前页 vs 未来页)。工程上 preload 精确指向关键资源,prefetch 用于路由级别预取。

preload 与 prefetch 的核心差异是"当前页急需"vs"未来页备用"。preload 影响 LCP,prefetch 影响后续导航。preload 过度使用会浪费带宽,prefetch 需谨慎预测。

#
★★

48. CDN 的边缘函数(Edge Functions、Cloudflare Workers、Vercel Edge)

请说明 CDN 边缘函数(Edge Functions、Cloudflare Workers、Vercel Edge)的工程应用?

  • 边缘函数的位置与运行环境
  • 典型用例(路由、鉴权、改写、A/B、SSR)
  • 局限与取舍

边缘函数(Edge Functions)在 CDN 边缘节点运行,代表有 Cloudflare Workers(V8 隔离)、Vercel Edge Functions、Netlify Edge Functions、Fastly Compute@Edge。它们在离用户最近的节点执行,延迟低、全球快速响应。典型用例:请求改写与重定向、边缘鉴权(校验 token)、A/B 测试与灰度分流、聚合第三方 API、缓存策略定制、JWT 校验、边缘 SSR/SSG 加速。局限:运行时资源受限(CPU/内存/超时)、平台 API 受限(不能直接用 Node 原生模块)、冷启动(部分平台)、调试较难。取舍:边缘函数适合轻量、低延迟、需要全球分布的逻辑;复杂/有状态逻辑应放回源站或 BFF。

边缘函数把"无服务器 + 就近执行"结合,适合处理单次请求的轻量逻辑。它与 CDN 缓存协同,实现"边缘动静态结合"。取舍核心是资源与复杂度边界。

#
★★

49. Stale-If-Error 缓存在后端故障时的工程降级策略

请说明 Stale-If-Error 缓存如何在后端故障时作为工程降级策略?

  • stale-if-error 指令语义
  • 后端故障时返回陈旧缓存
  • 与降级策略的配合

Cache-Control: stale-if-error=300 表示:当回源请求失败(如 5xx、网络错误)时,CDN/浏览器可以返回过期的缓存内容,而不是把错误返回给用户,从而在故障期间保持可用。它用于后端故障时的优雅降级:用户看不到错误页,而是看到最近一次的正确数据。工程价值:提高可用性,掩盖瞬时故障。但需注意:陈旧数据可能误导用户,需配合提示"数据可能不是最新";stale-if-error 只对已缓存内容生效,首次请求无缓存则仍失败。常与 stale-while-revalidate 组合,形成"缓存优先 + 故障兜底"的降级策略。

stale-if-error 本质是"缓存冗余抗故障"。它把"缓存"当"降级备份",在源站故障时用陈旧数据兜底。取舍是可用性 vs 数据新鲜度。

#
★★

50. Service Worker 的 Background Sync API 在离线数据同步的现代应用

请说明 Service Worker 的 Background Sync API 在离线数据同步中的应用?

  • Background Sync 的机制(注册同步任务)
  • 离线数据同步、网络恢复后重试
  • 与现代应用(弱网、表单提交)的配合

Background Sync API 允许应用注册后台同步任务,当网络恢复时(或条件满足时)在 Service Worker 中执行,即使页面已关闭也能同步。它适合离线/弱网场景下的数据同步:用户离线提交表单、发表评论、上传数据,先存入本地,网络恢复后 SW 自动上传。registration.sync.register('tag') 注册任务,SW 的 sync 事件处理器执行同步。工程价值:提升离线可用性、避免用户手动重试。现代浏览器对 Background Sync 支持较广(Chrome、Edge,Safari 支持有限)。需配合 IndexedDB 暂存待同步数据,并处理同步失败的重试限制。

Background Sync 把"同步"从页面生命周期中解耦,交给 SW 在网络恢复时执行。它解决"离线产生的数据何时上传"的问题,是离线优先应用的组成部分。

navigator.serviceWorker.ready.then(reg => reg.sync.register('sync-queued'));
// SW 中
self.addEventListener('sync', (e) => {
  if (e.tag === 'sync-queued') e.waitUntil(flushQueue());
});
#

51. CDN 的回源(origin)与缓存命中率优化的工程实践

请说明 CDN 回源与缓存命中率优化的工程实践?

  • 回源配置与源站健康
  • 提升缓存命中率(缓存键、缓存时长、预热)
  • 回源失败降级

CDN 回源(origin)是缓存未命中时从源站拉取的过程。优化命中率的工程实践:合理设置缓存时长(静态资源长缓存、动态按需短缓存);精简缓存键(去除无关 query、避免 Vary 碎片化);接口统一缓存键;对热点资源预热;避免 URL 带随机参数导致缓存穿透。回源配置需考虑源站健康检查、超时、重试与降级(stale-if-error、降级默认值)。命中率高的收益是回源少、延迟低、成本低。工程上通过监控缓存命中率与回源请求量评估优化效果。

缓存命中率是 CDN 性能的核心指标。命中率由"缓存键稳定性 + 缓存时长 + 内容唯一性"决定。优化命中率即减少回源,同时需保证回源失败时的降级。

#

52. HTTP 缓存验证器(ETag/If-None-Match)相较时间戳的工程取舍

请说明 HTTP 缓存验证器(ETag/If-None-Match)相较时间戳(Last-Modified)的工程取舍?

  • ETag 强验证器与 Last-Modified 弱验证器
  • If-None-Match 与 If-Modified-Since
  • 时间戳精度与内容变化检测

ETag 是强验证器,基于资源内容生成的哈希/版本号,能精确判断内容是否变化;Last-Modified 是弱验证器,基于时间戳,有秒级精度与内容未变但时间变的问题。缓存验证时,浏览器带 If-None-Match: <etag>If-Modified-Since: <date>,服务端比对后返回 304 或 200。ETag 更精确(能识别内容变化、避免时间戳歧义),但服务端需计算与存储;Last-Modified 简单但可能误判。工程取舍:对内容精确变化检测用 ETag;对实现简单、内容以时间区分的场景用 Last-Modified;最佳实践是两者都用(ETag 优先)。CDN 也常用 ETag 做缓存验证。

ETag 精于"内容是否真的变",Last-Modified 精于"是否在时间上变过"。取舍在于精确性 vs 实现成本,ETag 通常更可靠。

#

53. Cookie 缓存与 Cache API 在身份验证场景的工程协作

请说明 Cookie 缓存与 Cache API 在身份验证场景的工程协作?

  • 认证 Cookie 的存储与缓存约束
  • Cache API 缓存的认证响应
  • 避免缓存泄露与跨用户串数据

在身份验证场景,Cookie 负责携带会话(HttpOnly+Secure+SameSite),而 Cache API 缓存的响应若包含用户个性化数据,缓存到共享缓存会导致跨用户串数据与泄露。因此认证响应(如用户信息、个性化数据)不应被 CDN 共享缓存缓存,应设置 Cache-Control: no-storeprivate。Cache API 由 SW 控制,可缓存但需注意跨用户隔离(按用户、会话作为缓存键分区)。Cookie 与 Cache API 协作:Cookie 用于鉴权,Cache API 用于缓存非敏感公共资源;敏感认证数据不放缓存。工程上把"认证响应"与"可缓存公共资源"严格区分。

核心是"认证数据不该进共享缓存"。Cookie 与缓存的协作要避免个性化响应被缓存泄露。Cache API 可缓存但需按用户隔离,敏感数据用 no-store。

#

54. CDN 的边缘缓存与源站压缩(gzip、brotli)的工程协同

请说明 CDN 边缘缓存与源站压缩(gzip、brotli)的工程协同?

  • 源站压缩(gzip/brotli)与 CDN 缓存
  • 压缩与 Accept-Encoding 协商
  • 缓存压缩后的响应

源站压缩响应(gzip、brotli)减少传输体积,CDN 边缘缓存可缓存压缩后的响应。协同要点:源站按 Accept-Encoding 返回 gzip/brotli,CDN 缓存时需考虑压缩编码(Vary: Accept-Encoding 或统一压缩),避免给不同客户端返回错误编码。brotli 比 gzip 压缩率更高但 CPU 消耗大。工程上:源站对文本资源启用 brotli/gzip,CDN 缓存压缩后的响应并正确设置 Content-Encoding;命中缓存时直接返回压缩内容,回源时源站压缩。优化:CDN 可做压缩(在边缘压缩),减少源站 CPU。需注意缓存键区分不同编码,避免错误的 Content-Encoding。

压缩与缓存的协同核心是"编码一致性"。缓存需按 Accept-Encoding 区分(Vary 或统一),否则可能把 brotli 缓存返回给不支持 brotli 的客户端。边缘压缩可分担源站压力。

#

55. Cache Storage 的配额管理与清理策略的工程应用

请说明 Cache Storage 的配额管理与清理策略的工程应用?

  • Cache Storage 配额(navigator.storage.estimate)
  • 清理策略(版本管理、删除旧缓存)
  • 与 indexedDB 的存储竞争

Cache Storage 受浏览器存储配额限制,可用 navigator.storage.estimate() 查询已用与配额,navigator.storage.persist() 可申请持久化(避免被自动清理)。工程上需管理配额:SW 更新时删除旧版本缓存(caches.delete),定期清理过期缓存;与 IndexedDB 等其他存储共享配额,需统筹。清理策略:缓存策略确定可删除的旧缓存(如版本号),在 activate 时清理;对超配额的处理(catch 配额错误,降级到网络)。工程应用:避免缓存无限增长导致配额耗尽,影响 PWA 正常功能。

配额管理是 SW 缓存可持续性的关键。用版本化缓存 + activate 清理 + 配额查询,避免无限增长。持久化请求可降低被自动清理风险。

self.addEventListener('activate', (e) => {
  e.waitUntil(caches.keys().then(keys =>
    Promise.all(keys.filter(k => k !== 'app-v2').map(k => caches.delete(k)))
  ));
});
#

56. CDN 在边缘计算(Edge Compute)的 SSR/SSG 与中间件的现代应用

请说明 CDN 边缘计算(Edge Compute)在 SSR/SSG 与中间件中的现代应用?

  • 边缘 SSR/SSG
  • 边缘中间件(请求处理、鉴权、路由)
  • 与边缘缓存结合

CDN 边缘计算可运行 SSR(服务端渲染)与 SSG(静态生成)逻辑:在边缘节点渲染页面或用预渲染结果,配合边缘缓存实现全球快速响应。边缘中间件(如 Next.js Middleware、Vercel Edge Middleware、Cloudflare Workers)在请求到达前执行:路由、鉴权、重定向、A/B、请求改写。工程价值:SSR 在边缘就近执行减少延迟,SSG 结果由边缘缓存分发;中间件把边缘逻辑与页面渲染解耦。现代应用(Next.js 等)把页面渲染与边缘中间件结合,实现"边缘渲染 + 边缘缓存 + 边缘逻辑"。受限:边缘计算资源有限,复杂渲染仍需回源。

边缘计算融合了 SSR/SSG 与中间件:SSG 结果缓存于边缘,SSR 在边缘执行,中间件处理边缘请求逻辑。它们与边缘缓存协同,实现全球性能与动态能力的平衡。