HTTP / HTTPS / HTTP2 / HTTP3 与缓存策略

0 0

前言

做前端架构的人要不要懂 HTTP?我的回答是 ——不是去读 RFC 2616,而是建立”一次 HTTP 请求到底怎么走完”的工程直觉。原因有三:

  1. 首屏优化的天花板是网络层。HTML / CSS / JS 怎么优化都压不过 TTFB;HTTP/3 vs HTTP/1.1 在弱网下差距能到 300ms。
  2. 缓存策略决定二次访问速度。Cookie / Cache-Control / ETag / Service Worker 这些机制相互交织,配错一个就是”开发 OK 生产炸”。
  3. CDN / 边缘计算选型不靠直觉。Cloudflare / Fastly / Akamai 的协议支持差异巨大;HTTP/3 启用需不需要等运维、需不需要重写代码,依赖对协议栈的理解。

这一篇是『前端架构修仙路』的第 4 篇。我跳过 RFC 细节(不解释每个 header 的语法),用架构图 + 真实数据 + 选型决策表,把 HTTP 演进、TLS 握手、HTTP/2 多路复用、HTTP/3 QUIC、浏览器缓存讲透。下一篇聊前端安全(XSS / CSRF / CSP / SRI)。

一、HTTP 演进:从 1.0 到 3 的本质变化

1.1 演进时间线

图 1:HTTP 协议演进时间线

1.2 HTTP/1.1 的核心问题:队头阻塞

HTTP/1.1 引入了 Keep-Alive(连接复用)和 管道(pipelining),但实际收益远低于理论。原因:

  1. 请求-响应必须严格按序——客户端必须按顺序发出请求,按顺序收到响应。如果请求 1 的响应慢,请求 2-10 都要等。
  2. 连接数限制——浏览器对同一域名并发连接数有限制(Chrome 6 个),多出的请求排队。
  3. 队头阻塞(Head-of-Line Blocking)——TCP 层丢包会重传整个窗口,所有在飞的 HTTP 请求都卡住。

生产案例:顺丰 ERP 首页要加载 12 个 JS chunk(vendor、polyfill、4 个业务模块、路由、状态管理、监控、统计、SDK),HTTP/1.1 下需要 6 + 6 = 12 个 RTT(两批),单次首屏 = 6 × RTT

二、HTTP/2:二进制分帧与多路复用

HTTP/2 是 2015 年发布的协议大版本,解决了 HTTP/1.1 的核心问题。

2.1 核心机制:二进制分帧

HTTP/2 把 HTTP 消息(请求 / 响应)拆成更小的二进制帧,每帧带 stream ID 和 type。同一 TCP 连接上可同时跑多个 stream

TCP 连接 ── stream 1 (主 HTML)
       ├── stream 3 (CSS)
       ├── stream 5 (JS chunk 1)
       ├── stream 7 (JS chunk 2)
       └── stream 9 (image)

带来的好处

  • 一个 TCP 连接就够了(解决 HTTP/1.1 的 6 个并发限制)
  • 多路复用,没有 HTTP 层队头阻塞
  • 二进制帧解析快于文本协议

2.2 头部压缩 HPACK

HTTP/2 用 HPACK 算法压缩 header:

  • 客户端和服务端维护一张”header 字段表”
  • 重复 header 用索引号代替(节省字节)
  • Huffman 编码压缩字符串

生产数据:一个完整 HTTP 请求 header 大约 800 字节,HPACK 后能压到 30-50 字节。在 4G 弱网下,每个请求节省 ≈ 50ms

2.3 HTTP/2 的暗坑:TCP 层队头阻塞

HTTP/2 解决了 HTTP 层队头阻塞,但没解决 TCP 层队头阻塞。TCP 是按序交付的字节流:

TCP 窗口: [frame1 stream A] [frame2 stream B] [frame3 stream A]
                 ↓ 如果 frame2 丢失
                 ↓ TCP 重传
                 ↓ frame1 和 frame3 都得等

生产案例:跨太平洋链路丢包率 1-3%,HTTP/2 在这种链路下反而比 HTTP/1.1 慢——因为 1 个 TCP 包丢失会卡住整连接的所有流。这正是 HTTP/3 要解决的痛点。

2.4 Server Push(已废)

HTTP/2 引入了 Server Push——服务端主动推送资源(不需要客户端请求)。Chrome 107+ 已经移除 Server Push官方说明),原因是缓存命中率低、协议复杂度高。生产不要用

三、HTTP/3:基于 QUIC 的真正并行

HTTP/3 是 2022 年正式发布(IETF RFC 9114),用 QUIC 替代 TCP 作为传输层。核心突破UDP 之上的可靠传输

3.1 QUIC 为什么用 UDP

TCP 的核心问题:内核态实现,协议升级需要操作系统更新(几十年才推进一点点)。QUIC 把传输层逻辑搬到 用户态(在浏览器 / 应用进程里实现),协议升级只需要更新浏览器。

图 2:TCP vs QUIC 的协议栈对比

3.2 QUIC 解决了 HTTP/2 解决不了的问题

问题HTTP/2 (TCP)HTTP/3 (QUIC)
队头阻塞TCP 层丢包卡所有流每个 stream 独立,丢一不卡多
握手延迟TCP 三次 + TLS 三次 ≈ 2-3 RTT1-RTT 握手(QUIC 内置 TLS 1.3)
连接迁移WiFi → 4G IP 变 → 连接重置Connection ID 标识,IP 变不影响连接
拥塞控制内核级,跨平台不一致应用层,可差异化(BBR / Cubic)

生产数据:某海外业务从 HTTP/1.1 升 HTTP/3 后,高丢包率(5%)链路下首屏时间从 4.5s 降到 2.8s(节省 38%)。

3.3 HTTP/3 部署现状(2024)

浏览器支持版本备注
Chrome87+默认开启
Firefox88+默认开启
Safari14+默认开启
Edge87+默认开启

服务端支持:Cloudflare / Fastly / Nginx 1.25+(含 quiche 库)/ Caddy / Envoy / HAProxy 2.3+。启用只需配好证书和 UDP 443 端口

CDN 现状

  • Cloudflare 默认开启 HTTP/3
  • Fastly 可配置开启
  • AWS CloudFront 支持 HTTP/3(2023+)

顺丰 ERP 升级到 Cloudflare + HTTP/3 后,TTFB 从 800ms 降到 80ms(4.2s→1.8s 首屏优化的第一步)。

四、TLS 1.3:让 HTTPS 不再慢

4.1 TLS 1.2 vs 1.3 握手对比

图 3:TLS 1.2 vs TLS 1.3 握手时序

关键改进

  • 1-RTT 握手(首次连接)vs TLS 1.2 的 2-RTT
  • 0-RTT 握手(会话恢复)——客户端在第一帧就发加密数据
  • 移除了不安全的加密套件(RC4、SHA-1、DES)
  • 完全前向保密(Perfect Forward Secrecy)强制

4.2 OCSP Stapling:消除证书验证的额外延迟

传统 TLS 验证需要客户端查 OCSP(证书吊销状态),通常多 1 个 RTT。OCSP Stapling让服务端提前查 OCSP 并”装订”到 TLS 握手,客户端无需额外请求。

生产配置:Cloudflare 默认开启 OCSP Stapling;自建 Nginx 用 ssl_stapling on; ssl_stapling_verify on;

4.3 HSTS:强制 HTTPS

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

架构师必加:一旦上了 HTTPS,就给所有响应加 HSTS 头。生产案例:某中后台系统最初只对 /api 强制 HTTPS,但 /static 还是 HTTP,被中间人篡改后塞了广告。加 HSTS 后浏览器强制走 HTTPS,问题根治

五、浏览器缓存策略:Cache-Control / ETag / Service Worker

5.1 缓存层级

图 4:浏览器请求的 4 层缓存

匹配优先级:内存缓存 → Service Worker → HTTP 缓存 → CDN 缓存 → 源站。架构师要点:每一层都能省下一段 RTT。

5.2 Cache-Control 指令速查

# 静态资源(CSS / JS / 图片 / 字体)
Cache-Control: public, max-age=31536000, immutable
# 一年缓存,且不可变(带 hash 的资源)

# HTML 主文档
Cache-Control: no-cache, must-revalidate
# 每次都要向服务端验证(304 协商)

# 私有数据(用户相关)
Cache-Control: private, no-store
# 不缓存任何地方

生产规则

资源类型推荐 Cache-Control
带 hash 的 JS / CSS(如 app.abc123.jspublic, max-age=31536000, immutable
普通 HTMLno-cache, must-revalidate + ETag
API 响应(用户相关)private, no-store
公开 API 响应public, s-maxage=300, max-age=60
图片(不可变)public, max-age=31536000, immutable
字体public, max-age=31536000, immutable

5.3 ETag 与 304 协商

ETag(Entity Tag) 是资源的”指纹”,服务端给每个响应生成。客户端下次请求带 If-None-Match: <etag>,服务端比较:

  • 资源未变 → 返回 304 Not Modified无 body
  • 资源变了 → 返回 200 OK + 新内容

生产数据:300 KB 的 JS bundle,每次都下载 = 800ms。ETag 命中后 304 通常 < 50ms所以 hash bundle 一定要配 ETag

5.4 Service Worker 缓存策略

// stale-while-revalidate 模式:先返回缓存,后台更新
self.addEventListener('fetch', (e) => {
  e.respondWith(
    caches.open('v1').then(async (cache) => {
      const cached = await cache.match(e.request);
      const fetched = fetch(e.request).then((res) => {
        cache.put(e.request, res.clone());
        return res;
      }).catch(() => cached);
      return cached || fetched;  // 缓存优先,网络后台更新
    }),
  );
});

stale-while-revalidate 是 Service Worker 最常用的策略:用户秒开(缓存),后台拉新(更新),下次访问拿最新。

六、CDN 与边缘计算选型

6.1 CDN 的核心价值

CDN(Content Delivery Network)的核心是把内容推到离用户最近的边缘节点

未用 CDN: 用户 → 北京源站 = 200ms
用 CDN:   用户 → 边缘节点(就近) = 20ms

首屏 200ms 节省对 LCP 影响巨大。

6.2 主要 CDN 横向对比(2024)

CDNHTTP/3边缘计算中国大陆价格
Cloudflare✅ 默认Workers (JS)需 ICP免费层慷慨
FastlyCompute@Edge (Rust/Wasm)需 ICP中端偏贵
AkamaiEdgeWorkers需 ICP企业级贵
AWS CloudFrontLambda@Edge需 ICP按用量
阿里云 DCDNEdgeRoutine (JS)国内便宜
腾讯云 ECDNEdgeOne国内便宜

国内业务选型

  • 国内用户:阿里云 DCDN / 腾讯云 ECDN(必须 ICP 备案)
  • 海外用户:Cloudflare(免费层 + 简单配置 + 强 HTTP/3)
  • 混合:国内 + 海外双 CDN,DNS 分流

6.3 CDN 缓存策略

Surrogate-Key 模式(Cloudflare / Fastly 支持):给每个资源打 tag,让 CDN 支持按 tag 批量失效:

# 响应头
Cache-Tag: post-123, user-456, category-tech
# API 调用批量失效
POST /cache-tags/invalidate
{ "tags": ["post-123"] }

生产案例:某新闻网站首页用 Cache-Tag: frontpage;发新文章时调一次 /cache-tags/invalidate { "tags": ["frontpage"] }比传统”按 URL 失效”快 1000 倍

七、踩坑提醒(资深架构师请重点看)

  1. 不要盲目开启 HTTP/2 Push。Chrome 107 已删除 Server Push,Firefox 默认关。生产不要用
  2. 不要混淆 Cache-Control: no-cacheno-store。前者缓存在本地但每次验证;后者完全不缓存。HTML 用 no-cache + ETag用户数据用 no-store
  3. 不要忽略 HTTPS 升级的中间状态。HTTP → HTTPS 切换期间,HTTP 页面里的 HTTPS 资源可能被 mixed content 阻止加载。用 HSTS preload + 301 全站跳转
  4. 不要让 CDN 缓存 HTML。HTML 是动态生成的,CDN 缓存会导致用户看到旧版。HTML 用 no-cache,只在边缘做 SSL 卸载和压缩
  5. 不要忽略 HTTP/3 的 UDP 防火墙问题。部分企业内网和旧防火墙只允许 TCP 443。降级策略:HTTP/3 失败时自动回退到 HTTP/2(QUIC 握手失败会被浏览器透明处理)。

总结

这一篇用 7 个关键事实把网络协议栈串起来:

  • HTTP/1.1:队头阻塞 + 连接数限制 = 现代前端最大的优化目标。
  • HTTP/2:二进制分帧 + 多路复用 + HPACK,单连接多流是核心。
  • HTTP/3 + QUIC:UDP 之上的可靠传输,真正解决 TCP 队头阻塞
  • TLS 1.3:1-RTT 握手 + 0-RTT resume,HTTPS 不再拖慢首屏。
  • 缓存策略:Cache-Control + ETag + Service Worker 4 层体系。
  • CDN 选型:Cloudflare(海外)+ 阿里云/腾讯云(国内),HTTP/3 是默认选项。
  • TLS 1.3 + 0-RTT:HTTPS 不再慢。

下一篇:前端安全——XSS / CSRF / CSP / SRI,从攻击面讲清楚怎么写不漏。

5 道重点面试问题方向

Q1(答案):HTTP/1.1 升级到 HTTP/2 解决了什么核心问题?HTTP/3 又解决了 HTTP/2 解决不了的什么问题?

A:HTTP/1.1 三大痛点:① 连接数限制(浏览器同域名 6 并发);② HTTP 层队头阻塞(请求按序响应);③ header 重复传输(每个请求都带完整 cookie / UA)。HTTP/2 通过 二进制分帧 + 多路复用 + HPACK 头部压缩全解决——单 TCP 连接跑多个 stream,header 用索引表压缩。HTTP/3(QUIC)解决 HTTP/2 解决不了的 TCP 层队头阻塞——QUIC 在 UDP 之上重建可靠性,每个 stream 独立,丢一帧不卡其他流。还有 1-RTT 握手(vs HTTP/2 2-3 RTT)和连接迁移(IP 变不断连)。面试要点:能说 HTTP/2 的 “HPACK 状态表同步” 为什么不能跨连接复用。

Q2(思考):TLS 1.3 相比 TLS 1.2 在握手延迟上做了什么优化?0-RTT 模式有什么安全风险?

Q3(思考):CDN 的核心价值是什么?国内 + 海外混合业务应该怎么选 CDN?Surrogate-Key 比传统 URL 缓存失效好在哪?

Q4(思考):浏览器缓存有哪 4 层?各自适合什么场景?stale-while-revalidate 策略的取舍是什么?

Q5(思考):你在生产环境里是怎么把首屏时间从 4.2s 优化到 1.8s 的?网络层具体做了什么改动?

💡 每道题后面都有 AI 助手按钮,可以一键拿到详细答案。

参考资料

🔗 原文链接 分享让更多人看到

评论