CodeRoad Map 程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。
由 程序员柏风 独立维护 · 关于作者
学习 更多
HTTP/2 与 HTTP/3 多路复用、QUIC 概念。
HTTP/2 与 HTTP/3
这一课你将能做到
说明 HTTP/1.1「多开 TCP 连接硬扛并发」与 HTTP/2「单连接多路复用」各自如何解决并发问题,以及 TCP 层队头阻塞为何 h2 没根治
在 DevTools Network 打开 Protocol 列识别 h2 / h3 / http/1.1,并用 curl --http2 验证站点协议
列出对日常开发仍重要的三件事:TLS 前提、淘汰域名分片、协议升级不能替代压缩与缓存
为什么要学
打开 /tracks 要拉 HTML、CSS、JS、字体、API——HTTP/1.1 时代靠「每域 6 条 TCP 连接」硬扛,小文件多时握手开销和排队延迟很显眼。HTTP/2 在一条 TLS 连接上交错传多个流,HTTP/3 干脆把传输层换成基于 UDP 的 QUIC。
运维在 Nginx 开了 http2,前端却还在做「域名分片、合并文件」的 1.1 时代优化,收益被互相抵消——理解协议演进才能做对优化决策。面试问「HTTP/2 解决了什么问题、没解决什么」,答出「应用层队头阻塞解决了、TCP 层还在」就是高分答案。
先建立图像
HTTP/1.1 的困境:
每域约 6 条 TCP,每条同一时刻只能服务一个请求
→ 前一个响应慢,同连接后面的全排队(队头阻塞)
→ 小文件多时,握手/慢启动开销显眼
HTTP/2 的解法:
一条(通常 TLS)连接上多个 stream 并行交错
二进制分帧 + HPACK 头压缩 + 优先级
浏览器侧几乎总要求 HTTPS
HTTP/3 的再解法:
应用语义不变,传输层换 QUIC(UDP)
→ 单个流丢包不再拖死整条连接(流级独立恢复)
→ 换 Wi-Fi/切 4G 连接迁移不断线
对比表:
特性 HTTP/1.1 HTTP/2 HTTP/3 并发方式 多条 TCP 凑 单连接多 stream QUIC 上多流 报文格式 文本 二进制分帧 二进制分帧 头部 明文重复传输 HPACK 压缩 QPACK 压缩 传输层 TCP TCP QUIC/UDP DevTools 显示 http/1.1h2h3
跟着做
步骤 1:打开 Protocol 列,看看你天天访问的站在跑什么
打开 https://coderoadmap.cn/tracks
F12 → Network → 表头右键 → 勾选 Protocol 列
Ctrl+Shift+R 硬刷新,逐行看 document、静态资源、api/tracks 各自的协议
应看到:现代站点主流是 h2;第三方脚本可能还是 http/1.1(对方服务器没开);有 CDN 且支持时可能出现 h3。
步骤 2:curl 验证与强制协议
# 请求使用 HTTP/2(服务器需支持,否则自动回落 1.1)
curl -I --http2 https://coderoadmap.cn
# 看协商过程:ALPN 里应出现 h2 与 http/1.1 两个候选
curl -v --http2 -o NUL https://coderoadmap.cn 2>&1 | findstr /i "ALPN HTTP/2"
# Linux/macOS:curl -v --http2 -o /dev/null https://coderoadmap.cn 2>&1 | grep -iE "ALPN|HTTP/2"
# 强制只接受 HTTP/2,不支持就报错
curl -sI --http2-prior-knowledge https://coderoadmap.cn | head -n 1
若线上 --http2 只得到 HTTP/1.1 200,说明 Nginx/CDN 没启用 h2 或中间链路降级了。
步骤 3:给本机 Nginx 开 http2(可实操) server {
listen 443 ssl http2; # 1.25.1+ 也可写 listen 443 ssl; http2 on;
server_name localhost;
ssl_certificate /path/to/cert.pem; # 沿用 HTTPS 课的自签证书
ssl_certificate_key /path/to/key.pem;
location /api/ {
proxy_pass http://127.0.0.1:8080;
}
}
nginx -t && nginx -s reload
curl -sI --http2 https://localhost/api/hello -k | head -n 1
# 期望输出:HTTP/2 200
浏览器访问同样页面,Protocol 列会显示 h2——你亲手完成了一次协议升级。
步骤 4:数请求,体会多路复用的价值 在 Network 底部看「N requests / X transferred」;瀑布图里同域请求的彩色条明显并行起步 ,不再是一条等一条的阶梯。对比实验:找一个还在 1.1 的老站(或临时关掉 http2 on;),同样刷新——瀑布图呈串行长队。把两张截图存进笔记。
步骤 5:淘汰过时优化口诀 1.1 时代的优化 h2/h3 时代 域名分片凑 6 连接 停止:破坏单连接复用,还多几次握手 拼命合并 JS/CSS 成巨型文件 改为合理拆包:并行传输让小模块不再昂贵,但过大仍不利缓存 全部内联 CSS/JS 权衡:外链可独立长缓存(缓存课),h2 下内联收益下降 精灵图(Sprite) 逐图请求 + 缓存更灵活
仍然重要的:压缩(gzip/br)、图片体积、HTTP 缓存、CDN——协议更快不等于可以不裁剪数据 。
步骤 6:Server Push 的现状 HTTP/2 Server Push 曾被寄予厚望(服务器猜你要什么,提前推),实战命中率低、易推成重复资源,Chrome 已移除支持。现代替代:<link rel=preload>(页面自己声明关键资源)、HTTP 缓存、正确的优先级。新项目别把 Push 当必选项,面试答「已基本弃用、被 preload 取代」即可。
步骤 7:伪头与业务代码的分工 HTTP/2 线上报文用 :method、:path、:authority、:scheme 伪头承载请求要素:
stream A :method GET :path /tracks
stream B :method GET :path /_next/static/chunk-abc.js
stream C :method GET :path /api/tracks
(三条 stream 交错在同一条 h2 连接里飞)
DevTools 的 Headers 视图已翻译回熟悉的 Request Method/URL,curl -v 时可瞥见原文。业务代码继续按「方法 + 路径 + 状态码」思考 ——分帧是传输层的事,Controller 里不存在「操作伪头」这种需求。
排错口诀:若 Protocol 全是 http/1.1,先查 Nginx listen ... http2(或 http2 on;),再查是否被公司代理/老 CDN 降级,而不是改业务代码 。
讲清楚要点
因为浏览器对 HTTP/2 几乎总走 TLS,所以 h2 是 HTTPS 课的延伸而非平行知识 ——先有证书,再谈协议升级;明文 h2c 浏览器不用。
因为 h2 的多路复用仍在一条 TCP 上,所以一个包丢失会让 TCP 层重传阻塞所有 stream ——这是「h2 在高丢包网络可能不如多条 1.1 连接」的理论根源,h3/QUIC 用流级独立恢复解决。
因为 HPACK 压缩重复头,所以大量小 API 请求(重复 UA/Cookie)更省 ——但仍别无脑塞巨型 Cookie,压缩不改变「每请求都带全量头」的事实。
因为协议快不等于业务快,所以慢 TTFB 仍要查 SQL/缓存/逻辑 ——Network 的 Timing 分段看:DNS/TLS/TTFB/下载,优化手段完全不同。
因为中间盒可能禁 UDP/443,所以 HTTP/3 不一定处处可用 ——主流做法是 h3 与 h2 并行advertise,客户端按可达性选择;能稳定 h2 已是巨大收益。
因为应用语义未变,所以方法/状态码/头知识全部保值 ——升级传输层不需要重学 REST;本 track 前几课的内容在 h2/h3 下一字不改地成立。
你可能会懵的地方
都说 h2 消灭了队头阻塞,为什么面试官说没消灭?
h2 消灭的是应用层 「一连接一请求」的排队;但所有 stream 仍共享一条 TCP,TCP 只认字节流、不知道 stream 边界,丢一个包就得停流等重传——这是 TCP 层 队头阻塞。h3 把传输换成 QUIC(流之间独立恢复)才真正根治。
为什么我电脑上显示的还是 http/1.1?
依次排查:Nginx 没配 http2;中间有公司 SSL 检查设备或代理降级;用了不支持 h2 的老客户端;CDN 未开启。以 DevTools Protocol 列为准,别信文档口头承诺。
HTTP/3 一定比 h2 快吗?
弱网、高丢包、移动切换场景优势明显(0-RTT 恢复、连接迁移);稳定低丢包宽带上与 h2 差距不大。一切以实测为准,但开启成本已很低(Nginx 1.25+ 一行 listen 443 quic;)。
开发者要为 h2/h3 改业务代码吗?
几乎不用。要改的是部署配置(Nginx listen)与前端资源策略(去掉域名分片、重新评估合并策略)。Controller、状态码、头语义全部不变。
ALPN 在整个链路里扮演什么角色?
TLS 握手时客户端与服务端协商「用哪个应用协议」:客户端报 h2, http/1.1,服务端选一个。证书没问题但 ALPN 没协商到 h2,浏览器就回落 1.1——所以查协议问题时,curl -v 看 ALPN 行比看 Nginx 配置更直接。
同一页面又 h2 又 1.1 正常吗?
正常。主域走本站 h2,第三方脚本走对方 1.1;或 CDN 边缘支持 h2 而源站不支持。逐行看 Protocol,别看一条就下结论。
错法对照 错法 问题 正解 上了 h2 就不做缓存与压缩 协议只省传输开销,数据量照旧 协议 + 缓存 + 压缩三层叠加 继续「多域名分片」当优化 每个域多一条 TCP 握手,破坏单连接复用 同域 + h2/h3,让浏览器自己并发 把 Server Push 当新项目必选项 浏览器已移除支持,实战命中率低 用 <link rel=preload> 与缓存策略 TTFB 5 秒,却纠结协议是不是 h2 慢在业务/DB,不在传输 先看 Timing 分段与后端日志 以为 h2 改了方法/状态码语义 应用语义完全没变 语义照旧,照方法课/状态码课写代码
卡点急救
配了 listen 443 ssl http2 浏览器仍显示 1.1 :老版本 Nginx 与 http2 指令位置有讲究,nginx -V 看编译参数是否含 http_v2_module;浏览器与服务器之间若有企业代理/SSL 检查设备会强制降级——换手机热点网络验证。
开启 h2 后个别请求变慢 :h2 对同一连接上的大响应会占用带宽影响其它 stream;给静态大文件与 API 分域/分流,或开启 http2_body_preread_size 等调优。先用 Timing 确认慢在传输还是 TTFB,再动手。
想上 h3 但部分用户连不上 :UDP 443 被防火墙/运营商拦是常态。保持 listen 443 quic; 与 listen 443 ssl; 并存 + Alt-Svc 头 advertise,客户端探测失败自动回落 h2——设计目标就是「有则更快,无则照常」。
面试常问
HTTP/2 相比 HTTP/1.1 的主要改进?
① 二进制分帧:报文拆成帧,单连接可交错多 stream;② 多路复用:解决 1.1 一连接一请求的应用层队头阻塞;③ 头压缩 HPACK:去掉重复头;④ 服务器推送(现已弃用)与流优先级。附带:浏览器侧 h2 实际要求 HTTPS。
HTTP/2 的队头阻塞解决了吗?HTTP/3 呢?
应用层解决了,TCP 层没有:所有 stream 共享一条 TCP,丢包时整条连接的流都等重传。HTTP/3 用 QUIC(UDP)替代 TCP,流之间独立确认恢复,单流丢包不拖其它流,另有连接迁移(换网不断线)与更快握手。
为什么浏览器几乎只在 HTTPS 上提供 HTTP/2?
h2 规范要求 ALPN 协商,而 ALPN 是 TLS 扩展;明文 h2c 存在但主流浏览器不实现。后果是 h2 与 HTTPS 绑定部署——这也顺带把加密变成了现代 Web 的默认。
自测三问
HTTP/1.1 与 HTTP/2 各自如何实现「并行传多个资源」?瓶颈分别在哪?
如何在 Chrome 确认 /tracks 走了 h2?如何用 curl 验证并查看 ALPN 协商?
为什么说「协议升级不能替代 CDN 缓存」?各解决的是哪一层的问题?
小结一句话 HTTP/2 单连接多路复用、HTTP/3 用 QUIC 连 TCP 队头阻塞一起解决——应用语义始终是 HTTP,部署层开 h2/h3,应用层继续做好压缩、缓存与体积。
延伸