HTTP/2 与 HTTP/3
问题
HTTP/2 和 HTTP/3 相比 HTTP/1.1 有哪些改进?QUIC 协议是什么?
答案
HTTP/2(2015)和 HTTP/3(2022)是 HTTP 协议的重大升级,解决了 HTTP/1.1 的性能瓶颈。
版本演进
核心对比
| 特性 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 传输层 | TCP | TCP | QUIC (UDP) |
| 连接复用 | 管道化(有限) | 多路复用 | 多路复用 |
| 头部 | 文本,重复发送 | 二进制,HPACK 压缩 | QPACK 压缩 |
| 服务器推送 | ❌ | ✅ | ✅ |
| 队头阻塞 | HTTP + TCP 层 | 仅 TCP 层 | 无 |
| 加密 | 可选 | 推荐 | 强制 |
HTTP/1.1 的问题
1. 队头阻塞
2. 头部冗余
# 每个请求都发送重复的头部
GET /page1.html HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0...
Accept: text/html
Accept-Language: zh-CN
Cookie: session=abc123
# 即使请求同一域名,头部也重复发送
GET /page2.html HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0... # 重复
Accept: text/html # 重复
Accept-Language: zh-CN # 重复
Cookie: session=abc123 # 重复
3. 连接限制
// 浏览器对同一域名的并发连接数限制
// Chrome: 6 个
// 黑科技:域名分片(domain sharding)
// cdn1.example.com, cdn2.example.com...
HTTP/2 特性
1. 二进制分帧
// HTTP/1.1: 文本协议
"GET /index.html HTTP/1.1\r\nHost: example.com\r\n..."
// HTTP/2: 二进制帧
// +-----------------------------------------------+
// | Length (24) |
// +---------------+---------------+---------------+
// | Type (8) | Flags (8) |
// +-+-------------+---------------+---------------+
// |R| Stream Identifier (31) |
// +-+---------------------------------------------+
// | Frame Payload |
// +-----------------------------------------------+
2. 多路复用
// 单个 TCP 连接处理所有请求
// 请求和响应可以交错发送
// 彻底解决 HTTP 层队头阻塞
3. 头部压缩(HPACK)
// HPACK 压缩原理
// 1. 静态表:61 个常见头部
// 2. 动态表:连接期间构建
// 3. 霍夫曼编码:压缩值
// 示例:
// 请求1: { ":method": "GET", ":path": "/", "host": "example.com" }
// 请求2: { 静态表索引: 2, 静态表索引: 4, 动态表索引: 62 }
// 头部从 ~800 字节 → ~20 字节
4. 服务器推送
// 服务器可以主动推送资源
// 客户端请求 HTML 时,服务器同时推送 CSS 和 JS
// 请求 index.html
// 服务器返回 index.html
// 服务器推送 style.css (PUSH_PROMISE)
// 服务器推送 app.js (PUSH_PROMISE)
# Nginx 配置示例
location / {
http2_push /style.css;
http2_push /app.js;
}
注意
服务器推送在实践中使用较少,Chrome 已在 2022 年移除支持。 替代方案:103 Early Hints、preload。
5. 流优先级
// 可以为流设置优先级和依赖关系
// 例如:HTML > CSS > JS > 图片
// 优先级树
// 根
// / \
// HTML 图片
// / \
// CSS JS
HTTP/3 与 QUIC
QUIC 协议
QUIC(Quick UDP Internet Connections)是 Google 开发的传输层协议。
HTTP/3 优势
1. 消除队头阻塞
// HTTP/2 问题:TCP 是字节流,一个包丢失阻塞所有流
// HTTP/3 解决:QUIC 流独立,丢包只影响单个流
2. 更快的握手
3. 连接迁移
// HTTP/2: 连接由四元组标识 (源IP, 源端口, 目标IP, 目标端口)
// Wi-Fi → 4G,IP 变化,连接断开,需要重新建立
// HTTP/3: 连接由 Connection ID 标识
// IP 变化不影响连接,无缝切换
4. 内置加密
// QUIC 强制加密
// 握手过程即完成加密协商
// 没有不加密的 QUIC
启用 HTTP/2 和 HTTP/3
Nginx 配置
# HTTP/2
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
}
# HTTP/3 (需要 Nginx 1.25+)
server {
listen 443 ssl;
listen 443 quic reuseport;
http2 on;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# 告知浏览器支持 HTTP/3
add_header Alt-Svc 'h3=":443"; ma=86400';
}
检测协议版本
// 浏览器 DevTools → Network → Protocol 列
// JavaScript 检测
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.nextHopProtocol) {
console.log(`${entry.name}: ${entry.nextHopProtocol}`);
// h2 = HTTP/2
// h3 = HTTP/3
}
}
});
observer.observe({ type: 'resource', buffered: true });
常见面试问题
Q1: HTTP/2 相比 HTTP/1.1 有哪些改进?
答案:
| 改进 | 说明 |
|---|---|
| 多路复用 | 单连接并行请求,解决队头阻塞 |
| 二进制分帧 | 高效解析,减少错误 |
| 头部压缩 | HPACK 算法,减少传输量 |
| 服务器推送 | 主动推送资源 |
| 流优先级 | 重要资源优先传输 |
Q2: HTTP/2 还有什么问题?
答案:
TCP 层队头阻塞:
- HTTP/2 解决了 HTTP 层队头阻塞
- 但底层 TCP 仍然存在队头阻塞
- 一个 TCP 包丢失会阻塞所有 HTTP/2 流
Q3: HTTP/3 如何解决队头阻塞?
答案:
HTTP/3 使用 QUIC 协议(基于 UDP),流之间相互独立:
// QUIC 特性
// 1. 每个流独立,丢包只影响单个流
// 2. 不需要按顺序交付
// 3. 内置拥塞控制和重传机制
| 层级 | HTTP/2 | HTTP/3 |
|---|---|---|
| 应用层 | 多路复用 ✅ | 多路复用 ✅ |
| 传输层 | TCP 队头阻塞 ❌ | QUIC 无阻塞 ✅ |
Q4: QUIC 协议的特点?
答案:
| 特性 | 说明 |
|---|---|
| 基于 UDP | 用户态实现,快速迭代 |
| 0-RTT 恢复 | 首次 1-RTT,恢复 0-RTT |
| 无队头阻塞 | 流独立,丢包不影响其他流 |
| 连接迁移 | Connection ID 标识,IP 变化不断连 |
| 内置加密 | 强制 TLS 1.3 |
| 前向纠错 | 可选的 FEC 减少重传 |
Q5: 前端如何利用 HTTP/2 优化?
答案:
// 1. 停止使用雪碧图、合并文件
// HTTP/2 多路复用,小文件传输高效
// 2. 移除域名分片
// 单连接更高效,减少 DNS 和 TLS 开销
// 3. 合理使用服务器推送或 preload
// <link rel="preload" href="/critical.css" as="style">
// 4. 优化资源优先级
// <link rel="preload" ... fetchpriority="high">
// 5. 确保 HTTPS
// HTTP/2 实际上需要 HTTPS