三代 HTTP 核心差异一览
| 维度 | HTTP/1.0 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|---|
| 传输层 | TCP | TCP | TCP | UDP (QUIC) |
| 加密层 | 无 | 可选 TLS | 通常 TLS 1.2+ | 强制 TLS 1.3 |
| 连接复用 | 不支持 (短连接) | Keep-Alive 串行 | 多路复用 (单TCP) | 多路复用 (独立Stream) |
| TCP 队头阻塞 | 有 | 有 | 有 (TCP 层) | 彻底消除 |
| 头部压缩 | 无 | 无 | HPACK | QPACK |
| 服务端推送 | 无 | 无 | 支持 | 支持 |
| 建连 RTT | 每请求 1-RTT TCP | 复用后减少 | 1-RTT TCP + TLS | 0-RTT / 1-RTT |
| 网络切换 | 连接断开重建 | 连接断开重建 | 连接断开重建 | Connection ID 无缝迁移 |
| 协议位置 | 应用层 | 应用层 | 应用层 | 应用层 |
📊建连耗时对比 (相对)
以典型 RTT=50ms 为例,下面展示各协议从「开始连接」到「第一个字节返回」所需时间:
🧱协议栈 HTTP/1.x + HTTP/2
🚀协议栈 HTTP/3
⚡ QUIC 把 TLS 1.3 内嵌,加密握手和传输握手合并,不再需要单独的 TCP 握手阶段。
HTTP 1.0 & 1.1 底层原理
📌HTTP/1.0 — 短连接时代
- 连接模型每次请求单独建立 TCP 连接,响应完毕立即关闭
- 核心问题每个资源需要 3 次 TCP 握手 + 数据传输,巨大开销
- 头部信息纯文本,无压缩,重复发送 User-Agent / Cookie 等
- Host 字段不支持(一个 IP 只能挂一个网站)
- 缓存仅 Expires / If-Modified-Since
- 发布年份1996(RFC 1945)
🔧HTTP/1.1 — 改良优化
- Keep-Alive默认长连接,复用 TCP 连接,减少握手
- 管道化 Pipeline可连续发请求,但响应必须按顺序返回(问题根源)
- Host 头必须携带 Host,支持虚拟主机
- 分块传输Transfer-Encoding: chunked,无需预知 Content-Length
- 缓存增强ETag / Cache-Control / If-None-Match
- 发布年份1997(RFC 2068)/ 1999(RFC 2616)
🔄HTTP/1.0 单次请求完整流程
以访问一个 HTTPS 页面为例,每个资源都要走完整的 TCP 三次握手 + TLS 握手:
⚠️ 问题核心:HTTP/1.0 获取一个页面(HTML + 10 张图 + 5 个 JS)= 建立 16 条独立 TCP 连接,共耗费 16×3RTT = 48 个 RTT 光是握手!
🔌HTTP/1.1 Keep-Alive 原理
Keep-Alive 允许在同一个 TCP 连接上串行发送多个 HTTP 请求。服务器返回响应后不立即关闭连接,而是等待下一个请求。通过 Connection: keep-alive 头控制。
⚠️ Pipeline 的坑:虽然可以批量发请求,但响应必须 按请求顺序 返回。如果第 1 个请求处理慢,后面所有响应都被卡住 → HTTP 层队头阻塞。
HTTP/2 底层原理 — 二进制分帧 & 多路复用
🧩核心革命:二进制分帧层 (Binary Framing Layer)
HTTP/1.x 是纯文本协议。HTTP/2 在 TCP 与 HTTP 之间新增一个 二进制分帧层,把所有数据切成小的二进制帧(Frame),每帧带有 Stream ID,实现在同一个 TCP 连接上并发传输多个流。
🌊多路复用 (Multiplexing) 可视化
HTTP/2 的多个请求以不同 Stream ID 并发传输,帧交织在一条 TCP 连接中:
✅ 解决了 HTTP/1.x 的 HTTP 层队头阻塞。但由于底层仍是 TCP,如果某个 TCP 包丢失,TCP 的有序重传机制会导致 所有 Stream 都被暂停等待重传 — 这是 TCP 层的队头阻塞,HTTP/2 无能为力。
📦HPACK 头部压缩
静态表(Static Table):61 个常用头字段预定义,如 :method GET → 索引 2,直接用 1 字节代替。
动态表(Dynamic Table):首次发送的自定义头写入动态表,后续复用索引代替,大幅减少重复头传输。
🚨HTTP/2 的致命问题 — TCP 队头阻塞
本质:TCP 是字节流协议,要求有序可靠交付。如果一个 TCP 数据包(Segment)丢失,TCP 协议栈必须等待该包重传并收到后,才能把缓冲区里的后续数据交给上层。即使上层 HTTP/2 有 3 个流的数据已经全部到达,都得等那个丢失的包。
HTTP/3 底层原理 — 基于 UDP 的 QUIC 协议
💡为什么要抛弃 TCP,基于 UDP 自建协议?
TCP 的根本缺陷:
1. 队头阻塞:单个丢包卡住整个连接
2. 握手开销:每次建连至少 1-RTT TCP + 1-RTT TLS
3. 僵化:TCP 逻辑固化在操作系统内核,难以升级
4. 网络切换:IP 变化 → 连接断开,需重建(4元组绑定)
QUIC 的解法:
1. UDP 载体:UDP 只管发包,不排序,不阻塞
2. 应用层自实现可靠传输:Stream 独立确认,丢包只影响该 Stream
3. 用户态协议:运行在应用层,可快速迭代升级
4. Connection ID:不依赖 IP+端口,网络切换无缝迁移
🏗QUIC vs TCP+TLS 协议栈对比
内嵌
🔑QUIC 五大核心机制
① 独立 Stream(消灭队头阻塞)
每个 HTTP 请求对应一个独立 QUIC Stream。某个 Stream 丢包重传,只影响该 Stream,其他 Stream 正常传输。彻底消灭了 TCP 层的队头阻塞。
② 0-RTT 握手
首次连接:QUIC 握手 + TLS 1.3 合并,只需 1-RTT。
再次连接:客户端保存上次的 Session Ticket,直接发送数据,建连 0-RTT(比 TCP+TLS 少 2 个来回)。
③ Connection ID(连接迁移)
传统 TCP 连接由「源IP + 源端口 + 目标IP + 目标端口」四元组标识,手机从 WiFi 切到 4G 时 IP 变了,连接断开。QUIC 用自定义 Connection ID 标识连接,与 IP/端口无关,网络切换完全透明。
④ 改进的拥塞控制
QUIC 不依赖 OS 内核的拥塞控制,默认 Cubic,支持热插拔替换为 BBR 等算法,可针对不同网络场景快速迭代优化。
⑤ 强制加密
所有 QUIC 数据包(包括握手包)全部加密,连接元数据也加密,防止中间设备劫持(解决了 HTTPS 降级攻击问题)。TLS 1.3 内嵌于 QUIC 传输层,是不可绕过的设计。
⑥ QPACK 头部压缩
HTTP/2 的 HPACK 依赖单一有序流,HTTP/3 改为 QPACK,支持在多路并发 Stream 下安全高效压缩头部,不会因为乱序导致解压错误。
📡QUIC 0-RTT 握手流程
队头阻塞 — 三代协议的不同表现
🎯什么是队头阻塞(Head-of-Line Blocking)?
队头阻塞是指:在一个有序处理队列中,排在头部的请求/包因为某种原因阻塞了,导致队列中所有后续请求/包都必须等待,无法继续处理的现象。
在 HTTP 协议演进中,它在三个不同的层次被逐步解决:
📊队头阻塞层次对比
| 协议 | HTTP 应用层 HOL | TCP 传输层 HOL | 根本原因 |
|---|---|---|---|
| HTTP/1.1 | ❌ 存在(Pipeline) | ❌ 存在 | 响应必须按请求顺序 + TCP 有序交付 |
| HTTP/2 | ✅ 消除(多路复用) | ❌ 依然存在 | 二进制分帧解决应用层,但 TCP 层无法改变 |
| HTTP/3 | ✅ 消除 | ✅ 消除(UDP+独立Stream) | QUIC Stream 独立重传,丢包不跨 Stream 传播 |
握手开销对比 — 每 RTT 都是真实延迟
🔌TCP 三次握手
TCP 建立连接必须完成三次握手,耗费 1 个 RTT(Round Trip Time,往返时延):
TCP 握手后才能开始 TLS 握手,所以 HTTPS = 1RTT TCP + 1~2 RTT TLS。
🔐TLS 1.3 握手(HTTP/2 使用)
⚡QUIC 0-RTT — 握手与数据合并
0-RTT 的工作原理:客户端上次连接时,服务器会颁发一个 Session Ticket(会话票据),客户端保存。再次连接时,客户端在第一个 Initial 包里直接携带这个 Ticket + 加密的 HTTP 请求数据,服务器验证 Ticket 后直接处理请求,无需任何额外握手往返。