你的 API 处理的每个 HTTP 请求都运行在一层大多数开发者从未认真考虑过的传输层之上。25 年来,答案一直是 TCP。后来 Google 不再等待 TCP 改进,基于 UDP 构建了 QUIC 协议,IETF 又将其标准化。HTTP/3 就是构建在 QUIC 之上运行的 HTTP 版本。
这听起来像底层管道,而且大体确实如此。但这套“管道”会改变 API 建立连接的速度、API 在不稳定移动网络上的表现,以及并行请求共享连接的方式。如果你负责设计或运维 API,就应该了解哪些地方发生了变化、哪些没有变化,以及如何检查自己的接口目前使用的协议。
有一点始终不变:无论使用 HTTP/1.1、HTTP/2 还是 HTTP/3,你的请求、响应、状态码和 JSON payload 看起来都完全相同。像 Apifox 这样的工具在 API 层执行测试和调试,因此无论基础设施在底层协商哪一种传输版本,你对接口行为进行的所有验证都仍然有效。如果你已经读过我们关于 HTTP/2 是什么以及如何测试 HTTP/2 API 的解析,本文将从那里继续。
QUIC 协议是什么?
QUIC 是在 RFC 9000 中标准化的传输协议。它不依赖 TCP,而是运行在 UDP 之上,并在用户空间中按流重新实现 TCP 提供的功能(可靠性、有序传输和拥塞控制),从第一个数据包开始就内置加密。
四项设计决策定义了 QUIC:
它运行在 UDP 之上。 TCP 分布在互联网各处的操作系统内核和中间盒中实现,因此几乎不可能演进。UDP 只是一个不提供交付保证的薄封装,所以 QUIC 在其上构建自己的可靠性层,并可以通过更新库来发布改进,而不必升级操作系统。
TLS 1.3 是内置的,而不是后来附加的。 使用 TCP 时,你先完成 TCP 握手,然后再在其上完成单独的 TLS 握手。QUIC 将两者合并。加密设置本身就在传输握手中完成,因此建立新的安全连接只需一次往返。不存在未加密的 QUIC。
各个流相互独立。 一条 QUIC 连接可以承载多个流,每个流都会独立交付。丢失的数据包只会让它所属的流停顿。这正是对 TCP 队头阻塞(head-of-line blocking)的修复,稍后会详细说明。
连接可以在网络变化后继续存在。 TCP 通过 IP 地址和端口标识连接。只要其中一个发生变化(离开 Wi-Fi 覆盖范围、切换到 5G),连接就会断开。QUIC 改用 connection ID 标识连接,因此客户端可以切换到新网络,同时保持同一个逻辑连接存活。无需重新连接,也无需新的握手。
HTTP/3 在 RFC 9114 中定义,它将 HTTP 语义映射到 QUIC 流上。method 相同,header 相同,状态码也相同。线格式不同,传输层不同。
HTTP/3 与 HTTP/2:实际发生了哪些变化
HTTP/2 相较 HTTP/1.1 是一次重大进步。它引入了多路复用,让许多请求可以共享一条 TCP 连接,而不必排队或打开六个并行套接字。但它底层仍然使用 TCP,这带来了 HTTP/2 单靠自身无法解决的问题。
TCP 保证单个字节流按顺序交付。当一个数据包丢失时,TCP 会阻挡它之后的每个字节,直到重传到达,即使这些字节属于完全无关的 HTTP/2 流,也要如此。一个丢失的数据包会冻结连接上复用的全部 20 个请求。这就是传输层的队头阻塞,在有丢包的网络上,它可能让 HTTP/2 比使用多条连接的 HTTP/1.1 更慢。
HTTP/3 移除了共享字节流。每个请求都映射到自己的 QUIC 流,并拥有独立的交付顺序。如果承载流 5 的数据包丢失,流 6 到 24 仍会继续传输。多路复用终于按 HTTP/2 示意图一直宣称的方式工作。
握手的往返次数也发生了变化:
| 基于 TCP+TLS 1.3 的 HTTP/2 | 基于 QUIC 的 HTTP/3 | |
|---|---|---|
| 新连接建立 | 2 次往返(TCP + TLS) | 1 次往返 |
| 恢复连接 | 1 次往返 | 0 次往返(0-RTT) |
| 丢包影响 | 阻塞所有流 | 仅阻塞一个流 |
| 网络切换(Wi-Fi 到 5G) | 连接断开,需要完整重连 | 连接迁移,继续运行 |
| 加密 | 理论上可选,独立层 | 必需,集成 TLS 1.3 |
关于 0-RTT 这一行,需要补充一个注意事项。客户端重新连接到曾经连接过的服务端时,QUIC 允许它在握手完成前,就在第一个数据包中发送应用数据。这有助于降低延迟。但攻击者可能捕获并重放 0-RTT 数据,因此服务端在 0-RTT 中只能接受幂等请求。重放 GET 没有问题;重放一个会扣款的 POST 则不行。如果你在边缘节点启用 0-RTT,请确保排除非幂等 API 调用,或者确认你的 CDN 会替你完成这项处理。
HTTP/3 对 API 意味着什么
协议升级只有在能改变可测量的结果时才有意义。下面说明 HTTP/3 会在哪些方面改善 API 流量,以及哪些方面不会。
建立连接的开销降低
典型的移动客户端在 RTT 为 60 ms 的连接上,在第一个 API 请求离开设备前,TCP+TLS 建连大约要耗费 120 ms。HTTP/3 可将其缩短到约 60 ms,恢复连接时则接近于 0。对于经常建立新连接的移动应用(冷启动、后台唤醒、短时会话),每一个首个请求都能获得这项节省。对于维护热连接池的服务端到服务端集成,握手开销会被摊薄到几乎可以忽略,你不会感知到差异。
移动客户端不再频繁丢失连接
连接迁移是 API 团队容易忽视、但很有价值的特性。用户在办公 Wi-Fi 上发起请求,走到电梯后,手机切换到蜂窝网络。使用 TCP 时,这个进行中的请求会失败,你的客户端重试逻辑(你有重试逻辑,对吧?)会启动,并执行一次完整重连。使用 QUIC 时,连接会跟随设备迁移到新网络。客户端日志中的超时错误更少,也更少需要处理未完成一半的写入。
多路复用不再触发故障模式
对于 REST API,当客户端并行发起大量请求时,HOL blocking 修复最有价值:例如为 15 个小组件填充数据的 dashboard,或批量推送更新的同步引擎。在干净网络上,HTTP/2 和 HTTP/3 的表现大致相同。加入 1-2% 丢包(拥挤的会议 Wi-Fi、地铁蜂窝网络)后,HTTP/3 仍能让并行请求彼此独立,而 HTTP/2 会让它们整齐地一起停顿。
gRPC 目前大多仍使用 HTTP/2
gRPC 在设计上绑定 HTTP/2;其线协议契约依赖 HTTP/2 framing 和 trailers。gRPC 生态尚未标准化 HTTP/3 映射,主流实现(Go、Java、Python、Node)也没有提供它。.NET 的 Kestrel 服务端可以通过 HTTP/3 提供 gRPC 服务,但应将其视为例外。如果你的架构依赖 gRPC 和 HTTP/2 来提升内部 API 性能,今年无需规划 HTTP/3 迁移。
流式传输与实时流量
Server-Sent Events 在 HTTP/3 上无需变化即可工作,因为 SSE 是普通的长连接 HTTP 响应。WebSockets 更复杂:WebSocket 升级是为 TCP 设计的,其 HTTP/3 等价方案(RFC 9220,以及正在形成的 WebTransport API)支持情况参差不齐。如果你正在为实时功能权衡 WebSockets 和普通 HTTP,现阶段不应让 HTTP/3 的可用性左右决定。
实话部分:HTTP/3 什么时候帮不上忙
大多数 API 延迟问题与传输协议无关。如果接口因为未建立索引的数据库查询需要 400 ms,HTTP/3 只会让这个缓慢响应提前 60 ms 送达。缓存、payload 设计、N+1 查询和连接复用主导真实世界中的 API 性能;在考虑传输层之前,应先把这些方面优化到位。一次结构化的 API 性能测试通常会带来比协议升级大 10 倍的收益。
HTTP/3 在以下特定条件下最能发挥作用:
- 高延迟链路,节省往返时间可以带来固定比例的收益
- 有丢包的网络,消除 HOL blocking 的收益会叠加
- 会话中途切换网络的移动客户端
- 大量短连接,而非少量长连接
对于典型的 JSON API,如果同一区域的服务端通过可靠网络访问,差异在基准测试中可测量,但用户几乎感知不到。还有两点实践注意事项:某些企业网络会阻断 UDP 端口 443(客户端会自动回退到 HTTP/2,因此不会造成中断),并且与经过调优的内核 TCP 相比,QUIC 的用户态加密目前会为每个连接消耗更多服务端 CPU。
当前支持情况:今天谁支持 HTTP/3
其普及程度比大多数后端开发者想象的更高:
- 浏览器:Chrome、Edge、Firefox 和 Safari 默认都已启用 HTTP/3。
- CDN 和边缘节点:Cloudflare、Fastly、Akamai 和 CloudFront 都支持;在 Cloudflare 上只需切换一个开关。对大多数团队而言,实际可行的路径是:在边缘节点终止 HTTP/3,在边缘节点到源站之间继续使用 HTTP/1.1 或 HTTP/2。
- 服务端:Nginx 在 1.25 中加入了实验性的 HTTP/3 支持,配置为
listen 443 quic;。Caddy 默认启用它。LiteSpeed 和 HAProxy 支持它。Apache httpd 不支持。 - 运行时:Node.js 没有稳定的内置 HTTP/3 服务端支持,这也是边缘终止成为常见部署方式的另一个原因。
- curl:当使用支持 HTTP/3 的 TLS 栈构建时,可以通过
--http3参数支持 HTTP/3;具体哪些构建包含该功能,请参阅 curl HTTP/3 文档。
如何检查你的 API 是否提供 HTTP/3
发现过程通过响应 header Alt-Svc 完成。提供 HTTP/3 的服务端会在你的第一个(HTTP/2)请求中返回类似下面的内容:
alt-svc: h3=":443"; ma=86400
这告诉客户端:同一服务在接下来 24 小时内可通过 UDP 端口 443 使用 HTTP/3。使用 curl 检查它:
curl -sI https://www.cloudflare.com | grep -i alt-svc
# alt-svc: h3=":443"; ma=86400
要直接通过 HTTP/3 发出请求(需要构建时启用 HTTP/3 的 curl):
curl --http3 -I https://cloudflare-quic.com
# HTTP/3 200
状态行会报告 HTTP/3,而不是 HTTP/2。在 Chrome DevTools 中,打开 Network 标签页,右键点击列标题,启用 Protocol 列,然后在 API 调用旁查找 h3。在生产环境中,将协商出的协议加入访问日志;h2 与 h3 流量的比例可以告诉你有多少客户端获得了这项收益。
在验证传输层的同时,也要验证行为。将 Apifox 指向相同的接口,并针对状态码、响应数据模型和延迟预算进行断言。 如果底层 API 契约已损坏,传输层的收益毫无意义,而契约检查正是协议变化无法替你解决的那一层。在边缘节点启用 HTTP/3 前后,使用同一套测试用例;移动网络上的响应时间差异才是你的真实答案,而不是基准测试的标题。
常见问题
HTTP/3 比 HTTP/2 更快吗?
在干净、低延迟的网络上:几乎没有。在有丢包或高延迟的网络上:通常是的,而且差异往往很明显,因为 HTTP/3 节省了一次握手往返,并且单个丢失的数据包不再阻塞所有复用请求。在宣称有收益之前,请使用自己的流量特征进行测量。还要记住,HTTP/2 依然非常出色;如果在那里遇到连接错误,通常是 TLS 层问题,例如 SSLV3_ALERT_HANDSHAKE_FAILURE 问题,而不是协议本身的限制。
HTTP/3 使用 TCP 吗?
不。HTTP/3 运行在 QUIC 之上,而 QUIC 运行在 UDP 之上,通常使用端口 443。QUIC 在用户空间按流重新实现了 TCP 原本提供的可靠性、有序传输和拥塞控制。如果某个网络阻断 UDP 443,客户端会自动回退到基于 TCP 的 HTTP/2。
我需要为 HTTP/3 修改 API 代码吗?
几乎从不需要。HTTP 语义没有变化:method、header、状态码和 body 都相同。相关工作在基础设施中(在 CDN、负载均衡器或服务端启用 HTTP/3),此外还要做一项设计检查:确保 0-RTT early data 仅限幂等请求。
可以通过 HTTP/3 使用 gRPC 吗?
目前大多不行。gRPC 的线协议格式与 HTTP/2 紧密绑定,主流 gRPC 库也没有提供 HTTP/3 传输。.NET 提供实验性支持。让 gRPC 服务继续使用 HTTP/2,并优先在真正受益的地方采用 HTTP/3:面向公开用户、浏览器和移动端的 REST 接口。
开发必备:API 全流程管理神器 Apifox
介绍完上文的内容,我想额外介绍一个对开发者同样重要的效率工具 —— Apifox。作为一个集 API 文档、调试、设计、测试、Mock、自动化测试于一体的工具,Apifox 是目前提升研发效率的首选。
如果你正在开发项目,不妨试试其极其友好的界面设计,它完全兼容 Postman 和 Swagger 数据格式,导入数据非常方便,,即使是新手也能很快上手,点击这里即可注册使用。

值得一提的是,除了个人和常规团队使用,针对有高安全合规要求、或需要在内网环境协作的企业,Apifox 还提供了深度定制的私有化部署方案。
获取专属报价与部署方案
详细的私有化部署系统架构与安全白皮书
针对您公司规模的专属报价单
免费的 1v1 专属产品演示 (Demo) 机会