§ 10.1 · Section

HTTP/2 与 HTTP/3

Multiplexing · Head-of-Line Blocking · Binary Framing · QUIC · Alt-Svc

第 9 章的工具箱合盖时说过:接下来去看网络协议的"将来时"。但其实第一位主角早就不是将来时了——你现在打开的主流大网站,一半以上跑的已经不是教科书里那个 HTTP/1.1。第 3 章 § 3.1 讲的 HTTP 是"一问一答"的老式柜台:你说一句"给我这个页面",它回一句"给"。这个模型 1996 年设计、1997 年定型,那时候一个网页就是一张图加几行字,够用。可今天的网页动辄上百个文件——HTML、样式表、脚本、图片、字体、埋点——让老柜台一次接待一百位客人,它排队能排出天际。HTTP/2 和 HTTP/3 是对这个老柜台的两次彻底翻修:第一次翻修把"一个窗口一条队"改成"一个窗口同时办百样业务"(多路复用);第二次干脆连柜台底下的地基(TCP)一起换掉(QUIC)。两次翻修治好了什么、又各自留下了什么新病,就是这一节的主线。

生活场景
🧋 一家奶茶店的两次升级

十年前的小奶茶店,只有一个窗口、一支队伍:轮到你,报单,店员做,做好了递出来,下一位。后面的人哪怕只想买瓶现成的矿泉水,也得等前面那杯需要摇三次、加五样小料的"杨枝甘露"做完。
第一次升级:店家装了数字点单屏。你扫码下单,订单直接进后厨队列,谁先做好谁先叫号——窗口还是那一个,但没人再排队干等:三分钟出了七杯,杨枝甘露还在摇,不影响你的矿泉水先到手。可新问题跟着来:叫号屏和后厨之间只隔一条窄走道(内部传送系统),哪天一杯奶茶卡在走道里,做好的其他几杯也全堵在后厨出不来——顾客在窗口干着急,明明自己的那杯早就做好了。

第二次升级:店家痛定思痛,把"后厨—窗口"这条内部传送线整个拆了重建,每杯饮料走自己独立的小轨道。轨道 A 卡住,轨道 B、C、D 照常出货。

第一次升级是 HTTP/2(换点单系统),第二次升级是 HTTP/3(连后厨到窗口的传送系统都换了,这套新传送系统叫 QUIC)。两次升级针对的瓶颈根本不在同一层——这就是本节要讲清的全部。

先把这一节的术语翻译成人话

本节术语密度不低,照例先过一遍对照表,后面正文就不再解释这些词:

术语翻译成人话生活原型
HTTP/1.11997 年的老柜台——一问一答、串行排队单窗口奶茶店
HTTP/22015 年的大翻修——一次连接并行办百样业务数字点单屏
HTTP/32022 年定型的新一代——连传输地基都换掉重建传送轨道的门店
多路复用一条通道上交错跑多个任务,互不排队多股车道共用一条高速
队头阻塞队首卡住,后面全部干等珍珠卡住吸管,奶茶上不来
分帧把每个请求/响应切成带编号的小块大件家具拆成标准纸箱
一对请求响应的完整往来,由帧拼成一张订单的全部纸箱
头部压缩重复的表头信息只传变化的部分熟客点单说"老规矩"
QUIC在 UDP 上重建的新一代传输层快递公司自营车队
Alt-Svc服务器留的便条:"我也会说新协议"店门口贴"本店支持扫码点单"

前置史:从一张纸到一百个文件的二十年

要理解 2015 年为什么要大翻修,得先看清 1991 到 2015 这二十多年里,网页自己膨胀了多少。1991 年的 HTTP(后人追认的 0.9 版)简陋到只有一个动作:你敲一个词,它回你一个纯文本文件——没有请求头、没有状态码、连图片都不存在,因为 HTML 里的图片标签要到两三年后才被发明。那时候"一次请求"约等于"一张纸",一个网页就是一次往来,协议简陋得恰到好处。

1996 年的 HTTP/1.0 补齐了基本款:请求头、状态码、可以传任意文件类型——网页开始能放图了。但它的规矩是每个请求开一条新连接,用完就拆。看三个图片就是握手三次、挥手三次,铺张到肉疼。1997 年的 HTTP/1.1 是第一次重要修补:连接可以复用了(keep-alive 转正)、域名解析出的 IP 可以一台机器挂多个网站、缓存协商完善了——注意,1.1 的所有改良都发生在"减少浪费"的层面,串行排队这条主干从没被碰过。因为它设计时,谁也想不到网页会长成"上百个文件、几十个域名、实时长连接"的怪物。打个比方:一居室的设计图再怎么优化收纳,也塞不进一个六口之家——不是设计差,是需求变了天。

顺着这条时间线再看一遍开头那张表,你会多出一层体会:HTTP/2 不是对 1.1 的"修补",是"需求爆炸倒逼的重新设计"——网页长成了新物种,协议才不得不长成新物种。协议史的每一步,都是被使用方式推着走的。

先看老柜台:HTTP/1.1 到底怎么排队

先把时间拨回 2010 年前后的网页。你打开一个门户首页,浏览器干的第一件事是下载 HTML;读到一半发现里面有样式表、图片、脚本的地址,于是再一张张去要。在 HTTP/1.1 的规矩下,这些请求的走法是:建立一条 TCP 连接(§ 3.2 的三次握手),在这条连接上,请求一个接一个发,响应一个接一个回——像单车道过独木桥,谁也别想超车。

这就是第一个要害:串行。第 3 章 § 3.1 埋过一个词叫 keep-alive(持久连接)——它让这条 TCP 连接用完不拆、接着传下一个请求,省掉了每次重新握手的开销。§ 9.5 讲 TIME_WAIT 时还见过它:连接池的本质就是"让客人别走,常驻复用"。keep-alive 确实立了功,但它只解决了"重新建桥"的浪费,没动"过桥要排队"这个根本规矩——桥修得再久用,一次还是只能过一个人。

那让请求一起发行不行?HTTP/1.1 其实预留过这个后门,叫"管道化"(pipelining):请求可以连着发出去。但规矩有个死结——响应必须按请求的顺序回来。第一个请求是张加载要三秒的大图,第二个请求是行小字,小字也得等大图回完。说白了,管道化是"把单车道画成了双黄线",车队还是一条队——所以这个特性从生到死几乎没被真正用过,浏览器默认全关。

等到网页膨胀到几十上百个文件,这条单车道彻底顶不住了。但你可能纳闷:那些年的网页不也打开了吗?——因为浏览器在协议外面偷偷用了土办法,下一节就数一数这些"祖传偏方"。

三宗罪与一堆土偏方:浏览器是怎么硬扛的

把 HTTP/1.1 时代的账一次算清,它对现代网页有三宗罪:

浏览器和前端的应对是一堆今天看来啼笑皆非的偏方。浏览器给每个域名偷偷开 6 条连接——排队变 6 条队,效率翻了 6 倍,代价是握手翻 6 倍。前端工程师更绝:域名分片——故意把图片放到 img1.xxx.com、img2.xxx.com 好几个域名下,骗浏览器开更多连接;雪碧图——把几十张小图标拼成一张大图,用 CSS 裁着显示,只为把"几十个请求"压成"一个请求";代码内联——把样式和脚本直接塞进 HTML 里,同样为了省请求数。想象一下:因为收银台一次只能接待一位顾客,整个商场把所有商品打包成一个巨型包裹卖给你——这些偏方的存在本身,就是协议该升级的最好证据。(顺带一提:这些"黑历史"今天并没有死透——等会儿讲到 HTTP/2 时代它们如何一夜作废、又如何在新场景还魂,你会看到工程世界的钟摆。)

HTTP/2 第一板斧:把信件拆成标准纸箱

2015 年,HTTP/2 正式定稿(RFC 7540)。它的出身有意思:不是标准组织闭门造的车,而是 Google 的实验协议 SPDY 跑了几年、被证明真的快,然后"转正"。HTTP/2 的第一板斧,是把协议从"人读的文本"改成"机器拆的二进制"

老 HTTP/1.1 的报文是一封"手写信":请求行、一堆"名字: 值"的表头、空行、正文——好处是你拿 § 9.6 的 Wireshark 抓出来直接能读(Follow Stream 里那些 GET / HTTP/1.1 就是);坏处是机器解析文本协议又慢又容易出歧义——哪里是头哪里是尾?有没有多打一个空格?每个实现都得小心翼翼。HTTP/2 把报文改成了定长的二进制格式:所有内容切成一个个"帧"(Frame),每帧开头是固定的几个字节——长度多少、什么类型、属于哪个流(编号)。就像搬家时不再把家具随手乱塞,而是全拆成统一规格的纸箱,每个箱子贴上"张三家、第 3 箱"。收货方拿到箱子,看标签就知道归属,机器拆箱的速度比读信快得多,也不存在歧义。

这一板斧单独看只是"提效",真正的魔法在下一板——因为有了带编号的标准纸箱,不同请求的箱子才能混着装车。帧和流的关系一句话:流(Stream)是一对完整请求响应的往来(一张订单的全部纸箱),帧是流被切开的每一块(每只纸箱)。一个响应被拆成 100 只箱子,和别的响应的箱子交错发出,接收端按箱子上的编号各自拼回原样。本质上就是:先标准化了"货物单元",并行运输才有可能。

HTTP/2 第二板斧:一条车道,百股车流

第二板斧就是本节的主角概念——多路复用(Multiplexing):一条 TCP 连接上,无数个流的帧交错着跑,谁也不用等谁。

推演一遍新旧对比。HTTP/1.1 时代打开一个 80 个文件的页面:6 条连接各排一队,每队 13 个左右请求逐个来。HTTP/2 时代:浏览器和服务器之间只建 1 条连接,80 个请求的帧在这条连接上混着发——HTML 的第 5 帧、 logo 图的第 1 帧、脚本的第 3 帧……交错前行;后厨谁先做好谁先出货,先做完的小文件先交付,慢的大文件慢慢传,互不耽搁。回到奶茶店:老店里矿泉水必须等杨枝甘露;新店里扫码点单、先做先出。更要紧的是那个老病根被连根拔起——应用层的队头阻塞没了:一个慢请求再也拖不住别的请求。

把这个"混着发"画出来,一目了然。假设一条连接上同时跑三个响应——样式表(流 1)、大图(流 3)、小图标(流 5),它们在连接上是这样交错的:

   连接(一条 TCP,双向全双工)时间 →→→→→→→→→→→→→→→→→→→
   ┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
   │ 流1·帧1  │ 流3·帧1  │ 流5·帧1  │ 流1·帧2  │ 流3·帧2  │ 流5·帧2  │  ← 交错装箱
   │(样式表)  │(大图)    │(小图标)  │(样式表)  │(大图)    │(小图标)  │
   └─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
        ↓          ↓         ↓
   接收端按帧头的流编号各自归堆:
   流1 → ▓▓▓▓▓░░░░░  拼 齐 → 立即交付 ✓
   流3 → ▓▓▓░░░░░░░  拼到 20%(大,慢慢来)
   流5 → ▓▓▓▓▓▓▓▓▓▓  拼 齐 → 立即交付 ✓

看这张图要抓住两点。其一,连接上没有"队"这回事了——帧的先后不等于请求的先后,谁的数据在路上就发谁的,窄一点的连接也始终保持满载。其二,拼装发生在接收端:流 5 只有三帧,早早就拼齐交付了;流 3 是大文件,占着带宽慢慢传,但谁也不欠谁——各自的进度条各自走。这就是"多路复用"四个字的全部分量:一条物理通道,被帧头的编号切成了逻辑上无限多的并行车道。

多路复用落地的那天,前几节讲的那些土偏方集体失业,而且不是"没必要",是"有害":域名分片会逼浏览器开多条连接,而每条连接各自重新握手、各自慢慢爬升发送速度——恰恰拆了多路复用的台;雪碧图和内联把本可独立缓存的文件焊死在一起,改一个小图标整张大图缓存全作废。协议每翻新一次,上上代的最优实践就成了反模式——工程世界的规律,钟摆永远在荡。

还有一个静悄悄的收益值得单独一提:连接数从 6 条降到 1 条,服务器端意味着什么?一台要同时服务几万访客的网站,连接表压力骤降;对手机用户则意味着更省电——维持一条 TCP 连接的保活开销,远小于六条。第 3 章 § 3.2 讲拥塞控制时说过"TCP 爬坡"的脾气——新连接要从小速度试探着慢慢加速(这个话题 § 10.5 讲 BBR 时还要正式展开),现在 6 个慢慢爬的坡并成 1 个,全部流量一起喂给它喂饱。简单说:路少而精,好过路多而瘦。

HTTP/2 第三板斧:熟客点单,只说变化

第三宗罪(头部冗余)由头部压缩 HPACK 治理。它治病的思路,活脱脱是茶餐厅的场景:熟客进门不用背菜谱报全名,一句"老规矩,多冰少糖"就够——店员和你共享同一份"默认菜单",只传差异。HPACK 干的一模一样:客户端和服务器各自维护一份动态表,把见过的表头存进去;之后再发请求,重复的表头就用"表里第 7 项"一个编号代替,几十上百字节的 Cookie 变成两个字节。加上一张协议自带的静态表(最常见的几十个表头预置好了,比如"GET /"这种高频组合直接编号 1),以及对文本再套一层的哈夫曼编码——三招齐下,头部体积压掉九成是常态。

五十个请求、每个背着两 KB 相同 Cookie 的老场景,现在是第一个请求发完整版,后面四十九个基本只传增量。省的每字节在慢速手机网络上是实打实的毫秒。这一板斧没有前两板炫目,但有个值得记住的细节:头部压缩要求两端共享状态——动态表必须严格按序更新,谁错一格就全盘对不上。这为后面 HTTP/3 换传输层时添了一道小麻烦(QUIC 上乱序更自由,HPACK 的严格顺序反而成了负担,于是有了改版 QPACK——按下不表,§ 10.2 细说)。

并行之后的新问题:谁先谁后

多路复用一开,紧跟着冒出一个老协议从没操心过的新问题:一百个流并行抢一条连接,先发谁?HTTP/1.1 时代不存在选择困难——反正串行,来一个办一个。现在后厨一百张单子同时贴上来,如果服务器傻乎乎按到达顺序平均使劲,就可能出现:首屏要的 CSS 排在第八屏才用的广告图后面,页面白屏干等。这就引出 HTTP/2 的配套机制——流优先级:浏览器在开每个流时顺手贴张便签,告诉服务器"这个流重要,先传"。

优先级怎么定?浏览器心里有本账:HTML 是骨架,最急;样式表决定能不能画出来,次急;首屏图片再次;埋点统计、广告脚本这类"不催"的,垫底。相当于医院分诊台的工作——胸痛的进抢救室,感冒的坐着等号,不是谁先挂号谁先看,而是谁要紧谁先看。HTTP/2 把每个流标上权重和依赖关系(这个流压着那个流),服务器照着排发送顺序。到了 HTTP/3,这套机制简化升级成"紧急度"刻度盘,思路没变:并行世界必须有调度,否则并行只是把堵车从收费站搬进了停车场。

顺带把一个隐藏话题领出门:并行也让"流量控制"精细化了。§ 3.2 讲过 TCP 有流控——接收方嫌快了就喊慢点,防止被撑死。但 TCP 的流控是整条连接一把抓;HTTP/2 在自己这层又造了一套按流粒度的流控——大文件流别把小文件流挤死,哪个流收不住了单独给它降速,别的流照跑。这套"连接级粗调 + 流级细调"的双层设计,在 HTTP/3 的 QUIC 里原样继承。术语到此打住——你只需要带走那个画面:并行带来自由,自由立刻需要秩序;优先级是秩序的排序,流控是秩序的刹车。

好心办坏事:服务器推送的兴废

HTTP/2 还带着一个野心勃勃的第四板斧:服务器推送(Server Push)。逻辑听着无懈可击:浏览器要 HTML,服务器心想"他马上准会来要样式表和脚本,不如我主动塞给他",于是响应 HTML 的同时把 CSS、JS 一并推过去,省掉浏览器读完 HTML 再发请求的一来一回。

听着玄?其实就是店员看你点了牛肉面,顺手把辣椒罐和小菜端上桌——不用你开口。但现实给了这套逻辑一记闷棍:服务器猜,常常猜错。猜错的三种代价:浏览器已经缓存的文件,服务器不知道,白推一趟(浪费带宽);推了浏览器根本不需要的文件(更浪费);推送还有优先级风险——推错的大文件抢了正主的带宽,页面反而更慢。而"猜你需要什么"这件事,浏览器自己其实更擅长——它手里有缓存清单。于是各浏览器的态度从支持转为冷淡再到放弃:Chrome 在 2022 年正式移除了对 HTTP/2 推送的支持,这项特性事实上退场。接棒的是一个谦逊得多的替代品:服务器只发一条小小的提示信息(Early Hints,103 状态码)告诉浏览器"你待会儿大概率会要这几个文件",要不要、什么时候要,还是你自己定——从"替你做主"退回"给你透个信儿"。这段兴废值得记下:它演示了一个漂亮的工程教训——把决策权放在信息更全的那一端,比聪明地越俎代庖更可靠。

成绩单:HTTP/2 到底快了多少

三板斧下来,疗效如何?给 HTTP/2 开一张诚实的成绩单:

改善项机制体感
多文件页面加载多路复用消灭排队大改善——文件越多越明显
握手开销6 连接 → 1 连接明显——尤其高延迟网络
字节浪费头部压缩九成中等——Cookie 大的站点显著
单个大文件下载无对应机制几乎无提速

最后一行是这张成绩单上最容易被误读的一项,也是本节第一个反直觉常识:HTTP/2 治的是"排队病",不是"速度病"。下载一个 1GB 的安装包,走 HTTP/1.1 还是 HTTP/2 没区别——它没有排队可省,瓶颈在带宽本身。多路复用像把收银台从一队改成百队,但你买的东西本身要打包一小时,收银再快也没用。换句话说:HTTP/2 提速的是"很多人办很多事",不是"一个人办一件事"。(这也解释了一个流传甚广的怪现象:有人升级 HTTP/2 后测试单文件下载速度,得出"HTTP/2 更慢"的结论——多半是别的因素在捣乱,比如那条单连接在拥塞控制下爬坡没爬满,这正是 § 10.5 BBR 要接的话题。)

浏览器之外:HTTP/2 的另一个主场

讲到这儿你可能以为 HTTP/2 是"网页专用"——错,它还有一个远离浏览器、规模可能更大的主场:手机 App 和服务器之间的通信,以及服务器与服务器之间的内部通信。

想想你手机里的 App 是怎么工作的:一个购物 App 的首页要同时拉商品列表、购物车数量、消息红点、推荐位、优惠券状态——五六个请求同时发出,全对着同一台服务器。App 内部没有浏览器的"6 连接土办法"传统,HTTP/2 的单连接多路复用天然合身。更极致的是服务器集群内部:微服务架构里,一台业务服务器背后连着几十个数据库、缓存、下游服务,彼此调用每秒成千上万次——这里的多路复用省下的连接数、头部压缩省下的字节,乘上集群规模,都是真金白银的服务器成本。Google 当年力推的 gRPC——今天微服务世界最流行的通信框架之一——就是完全建立在 HTTP/2 多路复用之上:一次连接、百路调用,把"服务器之间的对话"也升级成了并行世界。

所以正确的理解是:网页只是 HTTP/2 最显眼的橱窗,"万物互相对话"才是它的完整版图。本节所有例子都拿网页打比方,只是因为网页人人看得见——但你要知道,深夜里数据中心内部那些机器之间的海量悄悄话,说的也是同一套话术。等 § 10.2 讲 QUIC 的长连接特性(连接迁移)时,你会看到 App 侧的收益比网页还大——手机切换网络的那一瞬间,正是 QUIC 最闪光的时刻。

没除根的病:TCP 层的队头阻塞

成绩单不错,但 HTTP/2 翻修完没多久,工程师们就发现了新瓶颈——而且这瓶颈的位置极其刁钻:不在 HTTP 自己那层,而在它脚下踩着的 TCP 那层。

复习 § 3.2 的关键设定:TCP 的承诺是可靠且有序——字节流按顺序交付给上层,中间丢了一个包,后面已到达的包也得在缓冲区里排队等重传补齐,谁也不许先走。这条规矩在 HTTP/1.1 时代无害:反正上层也是串行的,TCP 排序排得理直气壮。可 HTTP/2 把上层改成了百股车流并行——TCP 不知道也不关心"流"的存在,在它眼里,所有流的数据只是同一条字节大河。于是:流 A(那张大图)的一个包在路上丢了,TCP 停下等重传,此刻已经完整到达的流 B(那段小字体文件)的数据,全被堵在 TCP 的按序交付线上——明明流 B 一个字节都没丢,它也被流 A 的丢包株连了。

想象一下小区里那种一梯多户的老式筒子楼:HTTP/2 让每户人家各自收快递、互不干扰(多路复用),但整栋楼只有一部电梯(TCP 的按序交付)——电梯里只要有一件货卡住了,全楼所有人都下不来,哪怕你住二楼、走楼梯明明只要十秒。奶茶店版本一模一样:点单屏(HTTP/2)解决了排队,可后厨到窗口那条窄走道(TCP)只有一条,一杯卡住、全队堵死。这就是 TCP 层的队头阻塞——HTTP/2 的三宗罪全治了,唯独这条祖传的病根,动不了。因为它压根不是 HTTP 的病,是 TCP 的病。

为什么说"动不了"?修补 TCP 并非没人想过,但 TCP 是 1981 年设计、四十多年铺遍全球的地基——全世界每一台电脑、每一台路由器、每一个中间设备里都烧着它的实现。你想给 TCP 加新特性,就意味着全世界所有设备同时升级才生效——这件事在工程上约等于不可能。网络界给这个现象起了个学术名字:协议僵化(ossification)。地基太普及,普及到谁也改不动它。手术刀伸不进地基,那就只剩一条路:换地基。

QUIC 登场:在 UDP 的空地上重建传输层

换地基的方案 2012 年起在 Google 内部悄悄动工,名字叫 QUIC。它的思路一句话就能说透,但值得咀嚼三遍:放弃修补 TCP,改在 UDP 之上从零重建一个全新传输层。

为什么偏偏选 UDP 当地基(§ 3.3 的老朋友:快递柜式"放下就走"、不管顺序不管丢)?三层原因,层层递进。第一层最实际:UDP 足够"傻",傻到没人动过它——全球设备对 UDP 的处理方式几十年没变过,把新协议的数据塞进 UDP 的壳里,中间设备一律放行,不会像 TCP 新字段那样被沿途"好心"剥掉。QUIC 蹭着 UDP 这块谁也不设防的空地,绕开了协议僵化——相当于老城区改造无望,于是在城郊一块谁也没占的空地上,按新图纸平地起新城。第二层是部署速度:TCP 实现烧在操作系统内核里,升级 TCP 要等全世界的 Windows、Linux、macOS 发新版;QUIC 跑在"用户态"——就是普通应用软件的地盘,浏览器更新一版,新传输层就到位了,快慢差别是以年计的。第三层才是架构自由:从零设计,就再没有历史包袱——TCP 的按序交付那堵墙,新图纸里干脆不砌。

QUIC 的核心革新对着 TCP 的病根精准下刀:把"可靠且有序"的粒度从"整条连接"缩小到"每条流"。大图所在的流 A 丢了包?重传只在流 A 内部进行;字体所在的流 B 数据一到齐就交付,不再株连。筒子楼加装了分户电梯:301 家的家具卡在电梯里,302 照常上上下下。此外 QUIC 还把 TLS 1.3 的加密直接织进了协议本体(不再是"TCP 之上再叠一层 TLS"的两张皮)——安全从可选项变成了出厂标配,§ 8 章讲过的"默认不加密等于裸奔",在新一代协议这里被写进了基因。至于它握手快到什么程度(首访合并握手、回访 0-RTT)、换 WiFi 换基站为何不掉线(连接迁移)——这两项 QUIC 的招牌绝活,留到下一节专门拆解,本节先记住它的使命定位:一个为 HTTP/3 量身定制的、流与流互不株连的传输新地基。

HTTP/3:一次地基置换引发的版本跃迁

地基换了,上面的 HTTP 怎么办?答案是:HTTP 本身几乎原封不动,搬进 QUIC 的新房。换成大白话:搬家不换家具——人还是那家人,锅碗瓢盆原样打包,只是住进了新城。2022 年,HTTP/3 正式定稿(RFC 9114)——它就是"跑在 QUIC 上的 HTTP/2":多路复用、头部压缩、流、帧、优先级,这些 HTTP/2 的家当全数保留(头部压缩按新传输层微调成了 QPACK,前文提过)。方法论没变,变的是方法论脚下的物理学。

为什么叫 HTTP/3 而不叫 HTTP/2.5?版本号从 2 跳到 3,标志的正是这次传输层整体置换——它不是给 HTTP/2 打补丁,是换了一种 fundamentally 不同的运行方式。一个小细节最能体现这种"平行世界"感:HTTP/3 谈判不走老路。服务器第一次用 HTTP/2 回应你时,会在响应头里夹一张便条(Alt-Svc 头):"本店同时支持新协议,走 UDP 的 443 端口"。浏览器下一次访问就试着直接说 QUIC,说得通就再也不回头。这张便条像极了奶茶店门口贴的"本店支持扫码点单"——老顾客(老协议)照常排队,新顾客(新协议)扫码进新流程,两套体系长期并存、无缝切换,谁也不强制谁。这正是三十年来互联网协议演进的标准姿势:从不推翻重来,只并行生长。

你早就在用了:三分钟验证自己正跑在哪一代

这套听着前沿的东西,其实早就在你的浏览器里跑着了——说白了,验证它不需要任何专业知识。三个方法当场上手:

普及度给你一个诚实的坐标:主流浏览器(Chrome、Edge、Firefox、Safari)早已全量支持 HTTP/3;全球头部大站过半默认开启;公开网站整体的支持率在三分之一上下并逐年爬升——它是"已经发生、正在铺开"的现实,而非实验室展品。而老协议也没有死:大量中小站点、企业内网仍跑在 HTTP/1.1 和 HTTP/2 上,三代协议将长期同堂——毕竟 § 3.6 里那位 1981 年上岗的老将 TCP 至今仍在服务互联网的绝大多数流量,互联网从不急着退休任何还能干活的老兵。

一张总账:三代 HTTP 演进对照表

把三代协议的演进收进一张总账,这张表值得拍照存档——它是本节全部内容的浓缩,也是整章后四节的引子:

维度HTTP/1.1(1997)HTTP/2(2015)HTTP/3(2022)
传输层TCPTCPQUIC(UDP 上重建)
报文格式文本,人可读二进制分帧二进制分帧
并行方式串行 + 多开连接硬扛多路复用,单连接多路复用 + 流级独立
应用层队头阻塞
TCP 层队头阻塞有(被串行掩盖)有(新瓶颈)无(流间不株连)
头部压缩无,重复全量发HPACKQPACK
加密外挂可选实践中必配 TLS内置 TLS 1.3,标配
治好的病排队、握手、头部冗余层间株连、僵化地基
留下的病排队三宗罪TCP 队头阻塞?(留给未来)

看这张表的角度决定收获。横向看,每一代的主诉都清清楚楚:1.1 苦排队,2 治排队却苦株连,3 治株连——每一代都精准解决上一代的主要矛盾,又都留下新的次要矛盾。纵向看更值得玩味:HTTP/3 最后一格的问号不是偷懒——QUIC 也不是终点,它同样会在十年后变成"动不得的老地基"(别忘了 QUIC 自己已经为灵活升级做了机制预留)。不妨这样想:协议演进不是一场有终点的赛跑,而是一场接力——每一棒跑出自己的极限,然后把接力棒(连同自己的极限)交给下一代。技术史从不宣布"最终方案",只宣布"下一个方案"。

幕后花絮:协议是怎么"商量"出来的

最后补一块纯认知拼图,不考但值得看——本节反复出现的"RFC 7540""RFC 9114"这些编号,背后是一套延续几十年的全球协作机制。互联网的核心协议不是哪家公司发布的(那叫私有协议,比如前文提到的 Google SPDY 就曾是),而是由一个叫 IETF 的国际组织里各家公司、高校、个人的工程师坐在一起,一稿一稿吵出来、改出来、投票定下来的。一份 RFC 从草案到定稿,要经历几年公开评审:谁都能提意见,每条意见都要书面回应,浏览器厂商、服务器厂商、网络设备商互相牵制——所以协议才出现那么多"看似低效实则高明"的妥协设计(比如 Alt-Svc 这种"不强制、留便条"的协商方式,就是为了让保守方永远有退路)。

这套机制慢,但产出物极其可靠:一旦定稿,全世界照着同一份图纸施工,三十年不变形。SPDY 的故事是这套机制的教科书案例:Google 自己先造原型、拿真实流量验证几年、拿出实打实的性能数据,再交给 IETF 开放标准化——原型期的私有协议只是"提案",RFC 才是"法律"。顺便就能回答一个常见疑惑:既然 QUIC 也是 Google 发起的,凭什么信它不会变成 Google 的后门?因为交给 IETF 之后的 QUIC 与最初的私有版本已脱胎换骨——经过全球工程师逐条评审、重写加密设计、多家互操作验证,任何一方想夹带私货,都会在这一关被撕出来。协议演进快不起来,恰恰是因为它要对全人类的三十年负责。

把三代 HTTP 想成"一家奶茶店的三次进化"
第一代门店(HTTP/1.1):单窗口、一支队、一次办一单。客人多了,店家只会多开几个窗口(多开连接),装修队(前端工程师)则把几十样小料拼成一个套餐卖(雪碧图、内联)——生意能做,全员别扭。

第二代门店(HTTP/2):上了数字点单屏(二进制分帧)——所有订单变成统一格式的电子单,多单并行进后厨(多路复用),老规矩只报变化(头部压缩),店员还试过看你点面就主动端辣椒罐(服务器推送),结果端得太热心、频频端错,只好收手(Chrome 移除推送)。生意火爆,可一堵墙始终没动:后厨到窗口只有一条窄走道(TCP),一份卡住,全部堵住(TCP 层队头阻塞)。

第三代门店(HTTP/3):店家认清病根在走道不在点单——索性把店搬到隔壁新城(QUIC,在 UDP 空地上新建),点单系统原样搬过去(HTTP 方法不变),走道换成每人一条的传送轨道(流级独立),收银台直接焊上了保险柜(内置 TLS 1.3)。老店照常营业(TCP 并存),熟客看门口新贴的告示(Alt-Svc)自愿搬家,两店同堂、随来随选。

三代店的生意经一脉相承:客人(数据)越来越多、越来越急,那么第一代靠"排队",第二代靠"并行",第三代靠"谁也别拦谁"——排队→并行→独立,这条演进线,就是现代网络协议三十年的主旋律。

动手清单:把这一节摸出手感

常见误区

Recap · 收束

带走三句话。第一,两代翻修治的是两层病:HTTP/2 换了"柜台"——二进制分帧、多路复用、头部压缩,三板斧消灭排队与冗余;HTTP/3 换了"地基"——QUIC 在 UDP 空地上重建传输层,流与流互不株连,加密织进基因。第二,演进是接力不是革命:每一代精准解决上一代的主要矛盾(1.1 苦排队→2 治排队苦株连→3 治株连),旧协议不退场、新旧长期同堂,Alt-Svc 便条完成无缝换乘。第三,别高估也别低估它:多路复用提速的是"多文件页面",不是单个大文件;队头阻塞的根治是流级独立,不是更宽的带宽。

本节反复出现一个名字却始终没拆开讲:QUIC——它凭什么把 TCP 三次握手加 TLS 握手压成一次?0-RTT"零往返"是什么魔法?手机从 WiFi 切到 5G,视频通话为什么能不断线?下一节钻进这座新城的内部:QUIC 的握手与迁移,看新一代传输层的两招绝活。

☰ 主页
Xue Hai Wu Ya · Network · § 10.1 · HTTP/2 与 HTTP/3