HTTP/1.1 到 HTTP/3:从请求到流复用
0. 元信息
- 主题路径:
docs/topics/network/subtopics/http-1-2-3/ - 父主题:
network - 主分类:计算机基础
- 辅助分类:Web 与后端
- 适合对象:懂 TCP/UDP 三次握手与 socket 概念、会用
curl打 HTTP 请求、能读tcpdump抓包的学习者 - 建议周期:4~5 周(每周 6~8 小时,含抓包、命令行调试、协议分析)
- 前置知识:
tcp-and-udp(TCP/UDP、TLS 基础概念)、tls-and-https(握手、证书、ALPN);会curl/openssl s_client/tcpdump - 最终目标:能说清 HTTP/1.1 文本协议痛点、HTTP/2 二进制分帧与多路复用、HTTP/3+QUIC 为什么换 UDP;能用
curl --http2/--http3-only/nghttp2对比三版协议并解释抓包
1. 学习路线
HTTP 起源与请求/响应模型
→ HTTP/1.0 短连接与 keep-alive
→ HTTP/1.1 持久连接、分块传输、Host 头
→ 方法、状态码、Header 的语义
→ TLS 1.2/1.3 与 ALPN:HTTPS 握手
→ HTTP/2 二进制分帧、HPACK、流量/优先级
→ HTTP/2 多路复用与单连接并发
→ HTTP/3 + QUIC:UDP 之上的可靠流
→ QPACK 与 0-RTT
→ 实战:curl/nghttp2/wireshark 调试三协议
每一步配一组抓包;HTTP 文本协议要看到 raw 字节,HTTP/2 要看到帧,HTTP/3 要看到 CRYPTO 帧。
2. 阶段周数分配
| 阶段 | 4 周方案 | 5 周方案 | 备注 |
|---|---|---|---|
| 1. HTTP 语义与 1.0/1.1 | 0.75 周 | 1 周 | 必读 RFC 9110 关键章节 |
| 2. 方法、状态码、Header | 0.75 周 | 1 周 | REST 风格映射 |
| 3. TLS + HTTPS 握手 | 0.5 周 | 0.75 周 | ALPN 协商 |
| 4. HTTP/2 分帧与 HPACK | 0.75 周 | 1 周 | nghttp2 调试 |
| 5. HTTP/2 多路复用 | 0.5 周 | 0.5 周 | 单连接并发 |
| 6. QUIC 与 HTTP/3 | 0.5 周 | 0.5 周 | curl --http3-only |
| 7. 综合调试 | 0.25 周 | 0.25 周 | 三协议对比 |
3. 九阶段表
| 阶段 | 核心知识 | 实践产出 | 可观察学会标准 |
|---|---|---|---|
| 1. HTTP 起源 | Berners-Lee 1989 起源、CERN/MIT 文档、HTTP/0.9 → 1.0 | 一段 HTTP/0.9 请求/响应原始字节 | 能从 ASCII 字节读出请求方法、路径、版本 |
| 2. HTTP/1.0 vs 1.1 | 短连接、keep-alive、Host、Chunked、pipelining | curl -v http://... 看 1.0 与 1.1 区别 | 能解释 1.1 为什么强制要求 Host 头 |
| 3. 方法 / 状态码 / Header | GET/POST/PUT/DELETE/HEAD/PATCH/OPTIONS、2xx/3xx/4xx/5xx、Cache-Control、Authorization、Content-Type | 用 6 种方法请求同一资源,记录状态码与 Header | 能解释 401 vs 403、304 vs 200 from cache、409 适用场景 |
| 4. REST 与幂等 | 资源建模、URI 设计、幂等方法(GET/PUT/DELETE vs POST/PATCH) | 设计一个 5 资源的 REST API | 能解释 POST 与 PUT 的幂等差异 |
| 5. TLS 与 HTTPS | TLS 1.2/1.3 握手、ALPN、X.509、SNI、OCSP stapling | openssl s_client -alpn h2 -connect example.com:443 | 能从抓包看出 ALPN 选了哪个协议 |
| 6. HTTP/2 协议 | 二进制分帧、HEADERS/DATA/WINDOW_UPDATE/PING/PUSH、HPACK | nghttp2 -v https://example.com 看帧 | 能画出 9 字节帧头(length/type/flags/stream_id) |
| 7. HTTP/2 多路复用 | 单连接并发流、流量控制、优先级、server push | curl --http2 -v 看 stream id | 能解释为什么 HTTP/2 解决了应用层队头阻塞但没解决 TCP 层 |
| 8. QUIC 与 HTTP/3 | QUIC 头格式、CRYPTO 帧、流帧、连接迁移、0-RTT、QPACK | curl --http3-only -v https://cloudflare.com | 能说出 QUIC 相对 TCP+TLS 的三大改进 |
| 9. 综合调试 | 三协议对比、wireshark 解密、SSLKEYLOGFILE | 一份三协议对比报告 | 能在 15 分钟内从抓包判断请求走的是哪一版 |
4. 第一周任务
| 日 | 任务 | 当天交付 |
|---|---|---|
| Day 1 | curl -v http://example.com 看请求行/响应行/Header;telnet 手工敲一个 GET | 请求/响应原始字节标注 |
| Day 2 | curl -v --http1.0 对比 HTTP/1.0 与 1.1 的连接行为差异 | 一份差异记录 |
| Day 3 | openssl s_client -connect example.com:443 -alpn h2,http/1.1 看 ALPN 协商结果 | ALPN 输出 + 截图 |
| Day 4 | curl -v --http2 https://nghttp2.org 看 HTTP/2 协商;nghttp2 -v https://nghttp2.org 看帧细节 | nghttp2 帧日志 |
| Day 5 | curl --http3-only -v https://cloudflare.com 触发 HTTP/3;抓包看 CRYPTO 帧 | HTTP/3 抓包 + 帧说明 |
| Day 6 | wireshark + SSLKEYLOGFILE 解密 TLS;对照三协议抓包 | 三份解密 pcap |
| Day 7 | 项目:用 curl + nghttp2 把同一资源用三种协议都请求一遍,记录握手 RTT、首字节、复用一个连接并发 100 个请求的总耗时 | 一份三协议对比表 |
Day 7 拆解
步骤 A —— 最小可用(60 分钟)
- 选三个支持 HTTP/3 的目标,例如
https://cloudflare.com、https://www.google.com、https://nghttp2.org; curl -w '%{time_connect} %{time_starttransfer}\n' -o /dev/null -s https://host/跑三协议;for i in $(seq 1 100); do curl -s -o /dev/null https://host/ & done; wait测并发;- 记到
notes/week1-day7.md。
步骤 B —— 补齐边界(30 分钟)
- 关掉 HTTP/3:
curl --http2-only,重复对比; - 加 keep-alive 对比:
curl --keepalive-time 60; - 写报告:哪个协议在你本机到目标 CDN 的链路上最快。
进阶:稳定通过后,用
tc qdisc add dev eth0 root netem 100ms loss 1%模拟高延迟高丢包,重复三协议对比,看 HTTP/3 在丢包下的优势。
5. 阶段通用验收
- 不看 RFC 也能默写 HTTP/1.1 请求行 + 9 个常用状态码 + 5 个常用 Header;
- 用自己的话解释「HTTP/1.1 的队头阻塞」「HTTP/2 怎么缓解」「HTTP/3 为什么换 UDP」;
- 画一张图:HTTP/2 帧头 9 字节布局、HPACK 静态表、HTTP/3 CRYPTO 帧结构;
- 测试异常:5xx 服务端错、4xx 客户端错、3xx 重定向循环、TLS 握手中断、HTTP/2 GOAWAY;
- 准备 3 组自定义场景并贴抓包(HTTP/1.1 长连接、HTTP/2 多流并发、HTTP/3 0-RTT);
- 记录每个抓包的 BPF 过滤器、ALPN、stream id;
- 能修改 nginx 配置切换 HTTP/2 / HTTP/3,并验证切换。
6. 最终验收
- 独立完成:画 HTTP/1.1 请求/响应、HTTP/2 帧头、HTTP/3 包头;解释 HPACK 与 QPACK;用
curl --http3-only验证; - 至少完成 6 个实验(HTTP/1.1 keep-alive、HTTP/2 多路复用、HTTP/2 HPACK、HTTP/3 0-RTT、ALPN 协商、wireshark 解密);
- 完成 1 个综合项目:用
nginx+ 自签证书部署一个同时支持 HTTP/1.1 + HTTP/2 + HTTP/3 的小站,并用curl/nghttp2/wireshark验证三版都能正确握手; - 能用 15 分钟讲清楚 HTTP 从文本协议到二进制分帧到 UDP 之上重做的整条演进线。
7. 综合项目
首选:HTTP 三协议对比实验台(必做:本地 nginx 同时支持 h2 + h3,配合 openssl 自签证书;用 curl --http1.1/--http2/--http3-only 测首字节、握手 RTT、并发吞吐)。
备选:
- 用
nghttp2实现一个最小 HTTP/2 client(不要写完整协议栈,只验证 HEADERS 帧发送); - 抓一次生产环境 HTTP/3 流量,用 wireshark 解密 CRYPTO 帧;
- 用
h2c(HTTP/2 cleartext)跑一个 gRPC 服务并抓包。
综合项目必做要求:
- 场景描述:实验目标、对比维度、链路情况;
- 工具选择理由:为什么用
nghttp2而不是curl?为什么用openssl自签证书而不是 Let’s Encrypt? - 核心分析:每个协议的握手 RTT、首字节、并发吞吐对比;
- 复现脚本:可重复运行的 nginx 配置 + curl/nghttp2 命令;
- 边界测试:换网络条件(loss/RTT)下的对比;
- 运行说明:环境依赖(
nginx≥ 1.25、nghttp2、curl≥ 7.88、quictls或boringssl)、复现步骤; - README:项目介绍、目录结构、复盘;
- 复盘记录:用时、难点、收获、下一步。
复盘项目交付物统一存到 notes/:
notes/design.md:实验拓扑、对比维度、命令;notes/test.md:每组测试数据、期望、实际;notes/retrospective.md:踩过的坑与改进点。
本主题贡献
本主题沉淀 HTTP/1.1 文本协议(含 HTTP 缓存协商)、HTTP/2 二进制分帧 + HPACK、HTTP/3 over QUIC + QPACK 三代演进,所有结论用 curl --http1.1/--http2/--http3-only + nghttp2 -v + Wireshark(配 SSLKEYLOGFILE)三角验证。
职责(3 项)
- 解读 HTTP/1.1 请求/响应行、9 个常用状态码、Cache-Control/ETag/Last-Modified HTTP 缓存协商,能区分 200 from cache 与 304 Not Modified,能解释
Vary与If-None-Match双保险策略; - 抓 HTTP/2 9 字节帧头(length/type/flags/stream_id)、HPACK 静态表 61 项与动态表,能解释多路复用为什么解决应用层队头阻塞但没解决 TCP 层队头阻塞;
- 抓 HTTP/3 Long Header(Initial/Handshake/0-RTT)、CRYPTO 帧、QPACK encoder/decoder stream,能解释为什么 HTTP/3 抗丢包、为什么 0-RTT 只能用于幂等请求、为什么 connection_id 支持连接迁移(换 IP 不重连)。
交付物(4 项)
- 同一资源 HTTP/1.1 + HTTP/2 + HTTP/3 三协议对比表(
curl -w '%{time_connect} %{time_starttransfer}'+ 100 并发总耗时); nghttp2 -v https://nghttp2.orgHTTP/2 帧日志(SETTINGS/HEADERS/DATA/WINDOW_UPDATE/PING/GOAWAY),含 stream_id 与 END_STREAM 标注;curl --http3-only -v https://cloudflare.com抓包 +SSLKEYLOGFILE+ Wireshark QUIC 解密后的 CRYPTO 帧明文;- HTTP 缓存实验矩阵(
Cache-Control: max-age=N、ETag、Last-Modified、Vary)对同一资源的响应差异记录。
指标(3 项)
- HTTP/2 stream 复用率 ≥ 80%(100 并发请求平均每连接 stream 数);
- HTTP 缓存命中率 ≥ 60%(CDN/源站口径,
Age头统计); - 三协议首字节 TTFB 比:HTTP/1.1 > HTTP/2 > HTTP/3(同 CDN、同 RTT 链路,高丢包下 HTTP/3 反超更明显)。
8. 推荐开源资料(按角色分工)
| 角色 | 资料 | 链接 | 用法 |
|---|---|---|---|
| RFC 原文 | RFC 9110 — HTTP Semantics | https://www.rfc-editor.org/rfc/rfc9110 | HTTP 通用语义总览 |
| RFC 原文 | RFC 9112 — HTTP/1.1 | https://www.rfc-editor.org/rfc/rfc9112 | HTTP/1.1 现行规范 |
| RFC 原文 | RFC 7540 / RFC 9113 — HTTP/2 | https://www.rfc-editor.org/rfc/rfc9113 | HTTP/2 现行规范 |
| RFC 原文 | RFC 9114 — HTTP/3 | https://www.rfc-editor.org/rfc/rfc9114 | HTTP/3 映射层 |
| RFC 原文 | RFC 9000 — QUIC 传输 | https://www.rfc-editor.org/rfc/rfc9000 | QUIC 协议(与 tcp-and-udp 重复,建议在两处都列) |
| RFC 原文 | RFC 8446 — TLS 1.3 | https://www.rfc-editor.org/rfc/rfc8446 | TLS 1.3 握手 |
| RFC 原文 | RFC 7541 — HPACK | https://www.rfc-editor.org/rfc/rfc7541 | HTTP/2 头压缩 |
| RFC 原文 | RFC 9204 — QPACK | https://www.rfc-editor.org/rfc/rfc9204 | HTTP/3 头压缩 |
| 工具手册 | nghttp2 官方文档 | https://nghttp2.org/documentation/ | HTTP/2 client 与 server 实现 |
| 工具手册 | curl HTTP/3 文档 | https://curl.se/docs/http3.html | curl 的 HTTP/3 支持 |
| 工具手册 | nginx HTTP/3 配置 | https://nginx.org/en/docs/http/ngx_http_v3_module.html | nginx 启用 h3 |
| 工具手册 | man curl | man curl | 协议切换选项 --http1.1/--http2/--http3 |
| 中文讲解 | 字节跳动技术博客「HTTP/3 实践」 | https://web.archive.org/web/2024*/blog.csdn.net/ByteDanceTech | 工程视角 |
| 抓包练习 | Cloudflare HTTP/3 测试页 | https://cloudflare-quic.com/ | 在线验证 HTTP/3 |
| 抓包练习 | Wireshark QUIC 解密指南 | https://wiki.wireshark.org/QUIC | 解密 HTTP/3 抓包 |
许可证提示:nginx 是 BSD-2-Clause;nghttp2 是 MIT;curl 是 MIT/X;Wireshark 是 GPL-2.0。复制或参考命令前先确认许可证。
源码阅读时机:HTTP/2 实现源码(
nghttp2/lib/*.c)放到「阶段 6(HTTP/2 多路复用)」之后再读;RFC 原文从 Day 1 就开始对照,但不要试图一次通读——按当前阶段挑相关章节。
9. 学习资料汇聚(v0.3 自包含)
本节内容基于公开 RFC、nghttp2/curl 文档与个人整理,标注「由本计划生成」处为计划自写。本节是子主题自包含的最后一节,不再依赖
notes/子目录。
9.1 背景与动机
- 1989 年 Tim Berners-Lee 在 CERN 设计 HTTP,搭配 HTML 与 URL 三件套构成 Web 基础。最初 HTTP/0.9 只有一行 ASCII GET;
- 1996 年 HTTP/1.0(RFC 1945)正式版,引入 Header 与状态码,但每个请求独立 TCP 连接;
- 1997 年 HTTP/1.1(RFC 2068,1999 年修订为 RFC 2616,2022 年拆分重写为 RFC 9112)引入持久连接、分块传输、Host 头等,解决 1.0 的性能痛点;
- 2015 年 HTTP/2(RFC 7540,2022 修订 RFC 9113)从 Google SPDY 演化而来,引入二进制分帧、多路复用、HPACK 头压缩;
- 2018 年 IETF 决定 HTTP/3(RFC 9114)跑在 QUIC(RFC 9000)之上,QUIC 由 Google 设计、在 UDP 之上重做 TCP+TLS;
- 一句话总结:HTTP 的演进是一条「让一条连接干更多事、让握手更快、让丢包不再阻塞整条流」的连续优化。HTTP/3 换 UDP 不是倒退,是把 TCP+TLS 的工程问题在用户态重做。
9.2 概念地图
flowchart LR
App[应用层] --> HttpSemantics[HTTP 语义]
HttpSemantics --> H11[HTTP/1.1 文本]
HttpSemantics --> H2[HTTP/2 二进制]
HttpSemantics --> H3[HTTP/3]
H11 --> TLS[TLS 1.2/1.3]
H2 --> TLS
H3 --> QUIC[QUIC]
TLS --> TCP
QUIC --> UDP
H2 --> Frame[9 字节帧头]
H2 --> HPACK[HPACK]
H3 --> Stream[QUIC Stream]
H3 --> QPACK[QPACK]
H2 --> Mux[单连接多流]
H3 --> Mux2[无队头阻塞]
H2 --> Pri[流优先级]
H3 --> Migration[连接迁移]
关系说明:
- 三个版本共享 HTTP 语义(RFC 9110):方法、状态码、Header、缓存等「协议外」规则不变;
- HTTP/1.1 是 ASCII 文本,每请求独立或复用一条 TCP 连接;
- HTTP/2 把文本切成二进制帧,加 HPACK 压缩 Header;底层仍是 TCP;
- HTTP/3 把分帧与传输合并到 QUIC 流,底层是 UDP;HPACK 升级为 QPACK,因为 TCP 的有序字节流不再可靠。
9.3 基础知识讲解
经典论文 / 经典书籍 / 优秀博客 / 核心人物 / 开发方法 五大类,每类 ≥3 条。
经典论文 / RFC(必读)
| 资料 | 角色 | 评分 | 链接 |
|---|---|---|---|
| RFC 9110 — HTTP Semantics | HTTP 语义总览 | 5 | https://www.rfc-editor.org/rfc/rfc9110 |
| RFC 9112 — HTTP/1.1 | HTTP/1.1 现行规范 | 5 | https://www.rfc-editor.org/rfc/rfc9112 |
| RFC 9113 — HTTP/2 | HTTP/2 现行规范 | 5 | https://www.rfc-editor.org/rfc/rfc9113 |
| RFC 7541 — HPACK | HTTP/2 头压缩 | 4 | https://www.rfc-editor.org/rfc/rfc7541 |
| RFC 9114 — HTTP/3 | HTTP/3 映射层 | 5 | https://www.rfc-editor.org/rfc/rfc9114 |
| RFC 9000 — QUIC | QUIC 传输 | 5 | https://www.rfc-editor.org/rfc/rfc9000 |
| RFC 9204 — QPACK | HTTP/3 头压缩 | 4 | https://www.rfc-editor.org/rfc/rfc9204 |
| RFC 8446 — TLS 1.3 | TLS 1.3 握手 | 5 | https://www.rfc-editor.org/rfc/rfc8446 |
| SPDY 白皮书 | HTTP/2 起源 | 4 | https://www.chromium.org/spdy/spdy-whitepaper/ |
经典书籍(系统化)
| 资料 | 角色 | 评分 | 链接 |
|---|---|---|---|
| 《HTTP/2 in Action》(Barry Pollard) | HTTP/2 工程实战 | 5 | https://www.manning.com/books/http2-in-action |
| 《HTTP/3 Explained》(Daniel Stenberg,curl 作者) | HTTP/3 在线书 | 5 | https://http3-explained.haxx.se/ |
| 《High Performance Browser Networking》(Ilya Grigorik) | 浏览器视角的网络协议 | 5 | https://hpbn.co/ |
| 《Web Performance in Action》(Jeremy Wagner) | 性能调优 | 4 | https://www.manning.com/books/web-performance-in-action |
| 《Real World HTTP》(涩川喜规) | 实战经验 + 日本视角 | 4 | https://www.oreilly.co.jp/ |
优秀博客(按问题查)
| 资料 | 角色 | 评分 | 链接 |
|---|---|---|---|
| Cloudflare Blog「HTTP/3: the past, the present, and the future」 | HTTP/3 工程解析 | 5 | https://blog.cloudflare.com/http-3-the-past-present-and-future/ |
| Cloudflare Blog「An overview of HTTP/3」 | HTTP/3 抓包分析 | 5 | https://blog.cloudflare.com/http-3-the-past-present-and-future/ |
| Fastly Blog「HTTP/2 实务」 | CDN 视角 HTTP/2 调优 | 4 | https://blog.cloudflare.com/ |
| Robin Marx(HTTP/3 抓包权威) | HPACK/QPACK 深入 | 5 | https://github.com/rmarx |
| Daniel Stenberg(curl 作者)博文 | HTTP/3 与 curl 演进 | 4 | https://daniel.haxx.se/blog/ |
| Mozilla MDN HTTP 文档 | 协议查阅 | 4 | https://developer.mozilla.org/en-US/docs/Web/HTTP |
| 美团技术团队「HTTP/2 实践」 | 中文工程经验 | 4 | https://tech.meituan.com/ |
| 字节跳动技术博客 | 中文 HTTP/3 实践 | 3 | https://web.archive.org/web/2024*/blog.csdn.net/ByteDanceTech |
核心人物(知道谁定的规范)
| 人物 | 贡献 | 关键出处 |
|---|---|---|
| Tim Berners-Lee | HTTP/HTML/URL 设计 | 1989 备忘录 |
| Roy Fielding | REST 架构风格(论文影响 HTTP 方法设计) | 2000 博士论文 |
| Henrik Frystyk Nielsen | HTTP/1.0/1.1 编辑 | RFC 1945/2068 |
| Mike Belshe | SPDY 协议主设计者 | Google SPDY 白皮书 |
| Roberto Peon | HTTP/2 协议推动 | |
| Martin Thomson | IETF QUIC WG 主席、RFC 9114/9000 编辑 | IETF |
| Jana Iyengar | QUIC 设计核心 | IETF QUIC WG |
| Ryan Hamilton | HTTP/2 设计 | |
| Robin Marx | HTTP/3 抓包/HPACK 教学 | 独立研究者 |
| Daniel Stenberg | curl 作者、HTTP/3 布道者 | haxx.se |
开发方法(动手习惯)
| 方法 | 适用 | 关键点 |
|---|---|---|
curl -v 必开 | 所有 HTTP 调试 | 看握手、TLS、ALPN、HTTP 版本、Header |
curl --http2-only / --http3-only | 强制单协议 | 关掉降级,看真实协商 |
nghttp2 -v | HTTP/2 帧细节 | 比 curl 多出 SETTINGS/WINDOW_UPDATE/PRIORITY |
openssl s_client -alpn | TLS + ALPN | 看服务端协商出 h2 还是 http/1.1 |
SSLKEYLOGFILE + wireshark | 解密 TLS | 客户端设环境变量,wireshark 配置密钥日志路径 |
curl -w '%{time_connect} %{time_starttransfer}' | 测握手与首字节 | -w 模板化输出时间字段 |
--parallel 并发请求 | 验证多路复用 | curl 8.0+ 支持并发多 URL |
wireshark 解 QUIC | HTTP/3 抓包 | 配 SSLKEYLOGFILE 后才能看 CRYPTO 帧明文 |
tcpdump -nn -S 'tcp port 443' | 抓包 | 不加 -S 序列号是相对值 |
缺失部分:
nghttp2的--priorities选项语义、curl的--happy-eyeballs-timeout-ms取值。本计划不重写工具手册;查man curl/nghttp2 --help即可。
9.4 经典问题与经典案例
| # | 问题 | 为什么会重要 | 最简答案 |
|---|---|---|---|
| 1 | HTTP/1.1 队头阻塞 | 同一连接上后一个请求等前一个响应 | pipelining 不实用;浏览器并行开 6 条连接 |
| 2 | HTTP/2 应用层解决但 TCP 层没解决 | 一条 TCP 丢包阻塞所有 HTTP/2 流 | HTTP/3 换 UDP + QUIC 流解决 |
| 3 | HPACK 静态表与动态表 | 头压缩核心 | 静态表 61 项;动态表编码常用 Header |
| 4 | QPACK 为什么不能直接复用 HPACK | HPACK 假设 TCP 有序,QUIC 流独立 | QPACK 用单向编码器 + 解码器指令 |
| 5 | 0-RTT 重放风险 | 0-RTT 数据可被攻击者重放 | 0-RTT 只能用于幂等请求;服务端要绑定 client_random |
| 6 | 连接迁移(Connection Migration) | TCP 4 元组变就断连 | QUIC 用 connection_id,不依赖 4 元组 |
| 7 | ALPN 协商失败 | 服务端不支持 h2 但客户端默认走 h2 | openssl s_client -alpn h2,http/1.1 验证 |
| 8 | HTTP/2 GOAWAY 帧 | 服务端主动关闭,最后 stream id 通知 | 客户端收到 GOAWAY 后只发 ≤ 该 id 的请求 |
| 9 | HTTP/2 优先级争议 | 浏览器实现的优先级复杂、收益不稳 | RFC 9218(优先级)已标准化,但实现仍不一致 |
| 10 | QUIC 抓包解不出 CRYPTO 帧 | TLS 1.3 加密 | 用 SSLKEYLOGFILE 喂 wireshark |
| 11 | curl 默认走 HTTP/2 还是 1.1 | --http2 是尝试,--http2-only 是强制 | 后者失败直接报错而不是降级 |
| 12 | HTTP/3 公网部署比例 | CDN 部署了 h3 但小站未必 | https://cloudflare-quic.com/ 看自己网络支持情况 |
| 13 | 中间设备破坏 HTTP/2 | 某些老旧代理只认 HTTP/1.1 | 协商失败会自动降级,但性能打折 |
| 14 | PATCH 与 PUT 的幂等差异 | RFC 9110 明确区分 | PUT 替换整资源(幂等),PATCH 局部更新(非幂等除非自定) |
| 15 | 304 Not Modified 的强校验 | ETag / Last-Modified 不一致直接 200 | 用 If-None-Match + If-Modified-Since 双保险 |
9.5 学习难点
概念难点
| 难点 | 为什么会卡 | 突破路径 |
|---|---|---|
| HTTP 语义 vs 协议层 | 方法/状态码是协议无关 | RFC 9110 是「语义」,9112/9113/9114 是「协议」 |
| 帧、流、连接三者关系 | HTTP/2 一连接多流,每流多帧 | 画一棵树:Connection → Streams → Frames |
| HPACK 索引 vs 字面量 | 两类编码 | 抓包看到 :authority: example.com 标 (1) 索引 |
| QPACK 单向编码 | 编码器只发指令不阻塞 | 看 RFC 9204 的 encoder/decoder stream 图 |
| ALPN vs NPN | 两代 TLS 扩展名 | ALPN 是 TLS 1.2 后期引入,TLS 1.3 强制 |
| 0-RTT vs 1-RTT | 0-RTT 用上次 PSK | 抓包看第一个 ClientHello 后是否有 Early Data |
| connection_id 与 4 元组 | QUIC 抗迁移核心 | 抓包看 Initial 包 connection_id 字段 |
| HTTP/3 与 QUIC 关系 | QUIC 是传输,HTTP/3 是应用 | 类比 TCP vs HTTP/1.1 的关系 |
思维难点
| 难点 | 为什么会卡 | 突破路径 |
|---|---|---|
| 三层「队头阻塞」 | 应用层、传输层、加密层都会阻塞 | HTTP/2 解决应用层,QUIC 解决传输层 |
| 文本 → 二进制 → 流 | 抽象层跃迁 | 先看 raw 字节,再看 9 字节帧头,最后看 stream 帧 |
| 优先级到底要不要 | 实现复杂、收益不一 | 读 RFC 9218,浏览器实现优先级树 |
| HPACK 动态表 size 设置 | 太小压缩率低,太大吃内存 | nginx 默认 4 KB;按实际头调整 |
工程难点
| 难点 | 为什么会卡 | 突破路径 |
|---|---|---|
| curl 默认走什么协议 | 不指定就自动协商 | 加 --http2-only 或 --http3-only 排除歧义 |
| wireshark 解不出 HTTP/2 | 没设 SSLKEYLOGFILE | 客户端 export 该变量;wireshark 配置密钥日志 |
| nghttp2 抓不到 SETTINGS | 默认输出不够详细 | 加 -v 或 --verbose |
| QUIC 在公司网被屏蔽 | UDP 443 阻断 | 换 CDN 测;联系 IT 开放 UDP 443 |
| nginx 启 HTTP/3 需要 quictls | nginx 默认 OpenSSL 不支持 | 编译时用 quictls 或 boringssl |
| 自签证书客户端拒绝 | curl 默认严格 TLS | 加 -k 或 --insecure 临时绕过 |
| nghttp2 服务的 HTTP/2 抓包是乱码 | 加密 | 配合 SSLKEYLOGFILE |
9.6 技术标准与接口
9.6.1 Entity
| 名称 | 版本 | 发布组织 | 状态 | 许可证 / 可访问性 |
|---|---|---|---|---|
| HTTP Semantics (RFC 9110) | 2022 | IETF / HTTPBIS | 现行标准 | 免费公开 |
| HTTP/1.1 (RFC 9112) | 2022 | IETF / HTTPBIS | 现行标准 | 免费公开 |
| HTTP/2 (RFC 9113) | 2022 | IETF / HTTPBIS | 现行标准 | 免费公开 |
| HTTP/3 (RFC 9114) | 2022 | IETF / QUIC WG | 现行标准 | 免费公开 |
| HPACK (RFC 7541) | 2015 | IETF / HTTPBIS | 现行标准 | 免费公开 |
| QPACK (RFC 9204) | 2022 | IETF / QUIC WG | 现行标准 | 免费公开 |
| QUIC (RFC 9000) | 2021 | IETF / QUIC WG | 现行标准 | 免费公开 |
| TLS 1.3 (RFC 8446) | 2018 | IETF / TLS WG | 现行标准 | 免费公开 |
| curl | 持续更新 | haxx.se / curl 项目 | 工具 | MIT |
| nghttp2 | 持续更新 | tatsuhiro-t / nghttp2 项目 | 工具 + 库 | MIT |
| nginx (含 http_v3_module) | ≥ 1.25 | F5 / nginx 项目 | 服务器 | BSD-2-Clause |
9.6.2 Scope
- HTTP/1.1:文本协议,持久连接,分块传输,强制 Host 头;
- HTTP/2:二进制分帧,多路复用,HPACK,流量优先级,server push;
- HTTP/3:HTTP 语义 + QUIC 传输 + QPACK;
- HPACK / QPACK:Header 压缩算法;
- curl / nghttp2:调试客户端;
- nginx:服务器实现;
- wireshark + SSLKEYLOGFILE:抓包与解密。
不适用:实时双向通信(用 WebSocket、gRPC streaming、QUIC datagrams)、点对点文件传输(用 BitTorrent、WebRTC DataChannel)。
9.6.3 Structure
HTTP 请求/响应(HTTP/1.1 文本):
GET /index.html HTTP/1.1\r\n
Host: example.com\r\n
User-Agent: curl/8.0\r\n
Accept: */*\r\n
\r\n
HTTP 响应:
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Content-Length: 1234\r\n
\r\n
<body>
HTTP/2 帧头(9 字节):
| 偏移 | 字段 | 长度 | 说明 |
|---|---|---|---|
| 0-2 | Length | 3 字节 | 帧负载长度(不含帧头) |
| 3 | Type | 1 字节 | DATA=0x0 / HEADERS=0x1 / PRIORITY=0x2 / RST_STREAM=0x3 / SETTINGS=0x4 / PUSH_PROMISE=0x5 / PING=0x6 / GOAWAY=0x7 / WINDOW_UPDATE=0x8 / CONTINUATION=0x9 |
| 4 | Flags | 1 字节 | END_STREAM(0x1) / END_HEADERS(0x4) / PADDED(0x8) / PRIORITY(0x20) |
| 5-8 | Stream Identifier | 4 字节 | 31 位 stream id;最高位保留 |
QUIC Long Header(Initial / Handshake / 0-RTT):
| 偏移 | 字段 | 长度 | 说明 |
|---|---|---|---|
| 0 | Header Form | 1 位 | 1 = Long Header |
| 1-2 | Fixed Bit + Type | 2 位 + 4 位 | Initial=0, Handshake=2, 0-RTT=1 |
| 3-7 | Type-Specific | 5 位 | 包号低 5 位等 |
| 8-11 | Version | 4 字节 | 0x00000001 = QUIC v1 |
| 12-15 | DCID Len | 1 字节 + DCID | 目标连接 ID |
| 16+ | SCID Len | 1 字节 + SCID | 源连接 ID |
| 变长 | Token / Packet Number / Payload | 变长 | 含 CRYPTO 帧 |
常用方法与状态码:
| 方法 | 幂等 | 状态码 | 含义 |
|---|---|---|---|
| GET | 是 | 200 / 304 / 404 | 资源 / 缓存命中 / 未找到 |
| POST | 否 | 201 / 400 / 422 | 创建 / 客户端错 / 字段校验失败 |
| PUT | 是 | 200 / 204 / 409 | 替换成功 / 无内容 / 冲突 |
| DELETE | 是 | 200 / 204 / 404 | 删除 / 无内容 / 未找到 |
| PATCH | 否(除非自定) | 200 / 409 | 部分更新 / 冲突 |
| HEAD | 是 | 同 GET 但无 body | 元数据 |
| 状态码 | 含义 | 典型场景 |
|---|---|---|
| 1xx | 信息 | 100 Continue |
| 200 | OK | 成功 |
| 204 | No Content | DELETE/PUT 无 body |
| 301 / 308 | 永久重定向 | 永久迁移 |
| 302 / 307 | 临时重定向 | 表单 POST 后跳转 |
| 304 | Not Modified | 缓存命中 |
| 400 | Bad Request | 请求语法错 |
| 401 | Unauthorized | 未认证 |
| 403 | Forbidden | 认证但无权限 |
| 404 | Not Found | 资源不存在 |
| 409 | Conflict | 资源冲突 |
| 422 | Unprocessable Entity | 字段校验失败 |
| 500 | Internal Server Error | 服务端崩溃 |
| 502 | Bad Gateway | 上游错 |
| 503 | Service Unavailable | 服务过载 |
9.6.4 Ecosystem
- HTTP/1.1 实现:所有 HTTP 服务器与客户端;
- HTTP/2 实现:nginx ≥ 1.9.5、Apache ≥ 2.4.17、Caddy、HAProxy ≥ 1.8、Envoy、curl ≥ 7.36、nghttp2、OkHttp、Go
net/http; - HTTP/3 实现:Cloudflare CDN、Facebook proxy、nginx ≥ 1.25(带 quictls)、Caddy ≥ 2.4、curl ≥ 7.66(带 quictls)、nghttp3、quiche(Rust)、msquic、mvfst;
- QUIC 库:quiche(Cloudflare,Rust)、msquic(Microsoft,C)、quic-go(Go)、nghttp3(C);
- HPACK 实现:nghttp2、curl、Go
net/http2; - QPACK 实现:nghttp3、quiche、quic-go;
- 事实标准 vs 标准本身:
- 默认 HTTP 版本:浏览器普遍支持 HTTP/2,HTTP/3 还在推广;
curl默认 HTTP/1.1,加--http2升级尝试,加--http3-only强制;- 浏览器
Alt-Svc头:服务端告诉客户端「我同时支持 h3,可以升级」。
9.6.5 Depth Tiers
| 层级 | 名称 | 必须看到什么 |
|---|---|---|
| L0 | 知道存在 | 知道 HTTP/1.1 文本、HTTP/2 二进制、HTTP/3 在 QUIC 上 |
| L1 | 看得懂示例 | 看到 curl -v 输出能猜到握手、Header、状态码 |
| L2 | 能正确调用 | 能用 curl --http2 / --http3-only 切换协议并解释返回 |
| L3 | 能解释与排错 | 能解释 HPACK/QPACK、0-RTT、ALPN、GOAWAY |
| L4 | 能设计与扩展 | 能写 nginx 配置启用 h2+h3,能用 nghttp2 库写最小 HTTP/2 client |
本计划目标:阶段 9 综合调试时达到 L3。
9.6.6 Source
- RFC Editor:所有 HTTP/HTTP2/HTTP3/QUIC/TLS 原文(
https://www.rfc-editor.org/); - IANA HTTP/2 Settings Registry:HTTP/2 设置参数权威分配(
https://www.iana.org/assignments/http2-parameters/); - curl 官方 HTTP/3 文档(
https://curl.se/docs/http3.html); - nghttp2 官方文档(
https://nghttp2.org/documentation/); - nginx HTTP/3 模块文档(
https://nginx.org/en/docs/http/ngx_http_v3_module.html); - Cloudflare HTTP/3 技术博客(
https://blog.cloudflare.com/); - 引用版本快照日期:2026-07-30。
10. 常见误区
- 把 HTTP/3 = QUIC:QUIC 是传输,HTTP/3 是其上的 HTTP 映射;
- 把
--http2当成强制:它只是「尝试」,服务端不支持会降级;用--http2-only; - 抓包不设
SSLKEYLOGFILE:所有 TLS 1.3 加密流量都是乱码; - 用
time curl测延迟:握手 RTT 不止一次;用curl -w '%{time_connect}'; - 把 HTTP/2 多路复用等同 WebSocket:HTTP/2 仍是请求-响应,WebSocket 是双向流;
- 改 nginx 配置不 reload:
nginx -s reload漏了导致无效; - 把
Server: nginx/1.25当成 HTTP 版本:那是服务器软件版本,与 HTTP 协议版本无关; - 启 HTTP/3 用默认 OpenSSL:编译时需要
quictls或boringssl,否则启动失败; - 用
curl -k当成万能测试:自签证书场景可用,生产环境看到-k要警觉; - 用浏览器开发者工具看 HTTP 版本:Network 面板只能看 HTTP/1.1 vs HTTP/2,HTTP/3 不显示;用
chrome://net-export或 wireshark; - 把 PATCH 当成幂等:默认非幂等,自定义协议可定义幂等;
- 客户端用 HTTP/2 但服务端只支持 HTTP/1.1:不报错,只是降级,调试时容易忽略;
- nginx 配置
add_header不生效:可能是add_header在if块里被跳过;改用map或写在更高层级; - 启用了 HTTP/2 但没启用 HTTPS:浏览器只支持 HTTP/2 over TLS,明文 HTTP 仍是 HTTP/1.1。
11. 所有知识点分类(统一规则)
按本仓库统一分类规则(与父主题一致):
- 编程语言
- 数据结构与算法
- 计算机基础:网络协议、操作系统、组成原理
- 工程技术
- Web 与后端:HTTP、REST、Spring Boot、数据库开发等
- 前端与客户端
- 数据与人工智能
- 项目与职业能力
本计划归属:计算机基础 主 + Web 与后端 辅。