savearoundtrip: 发布 HTTPS DNS 记录,跳过一轮往返
摘要
savearoundtrip 是一个工具,用于检查域名是否发布了 HTTPS DNS 记录以宣传 HTTP/3 支持,从而使浏览器在首次连接时通过立即使用 QUIC 来跳过一轮往返。
<p><a href="https://lobste.rs/s/wlm6dv/savearoundtrip_publish_https_dns_record">评论</a></p>
查看缓存全文
缓存时间: 2026/06/15 19:01
# savearoundtrip
来源:https://savearoundtrip.com/
savearoundtrip检查域名(https://savearoundtrip.com/#check)成本(https://savearoundtrip.com/#cost)问题(https://savearoundtrip.com/#why)为什么选择HTTPS(https://savearoundtrip.com/#how)数据(https://savearoundtrip.com/#data)发布(https://savearoundtrip.com/#publish)FAQ(https://savearoundtrip.com/#faq)## 在HTTPS DNS记录中宣告HTTP/3支持,而不仅仅是Alt-Svc头部,浏览器即可在首次连接中使用HTTP/3(QUIC)。
浏览器发现网站支持HTTP/3有两种方式:要么先通过HTTP/1或HTTP/2连接,读取其`Alt-Svc`HTTP头部;要么立即通过**HTTPS DNS记录**查询获知。只有借助HTTPS DNS记录,浏览器才能在首次连接中使用HTTP/3,从而通过QUIC节省一次往返时间。
...
在Firefox Nightly中,有...的连接仅在**后续**连接时才达到HTTP/3:这些网站仅在`Alt-Svc`HTTP头部中宣告了HTTP/3支持,而非DNS中,尽管它们本可以同时发布两者。若发布HTTPS记录,则可为这些连接的首次连接各节省一次往返时间。
正在从GLAM加载数据...
## 检查域名
本网站吃自己的狗粮:savearoundtrip.com (https://savearoundtrip.com/#check) 发布了一个包含h3、IP提示和ECH的HTTPS记录。
HTTPS记录通过你的浏览器,经由Cloudflare的DNS-over-HTTPS端点进行查询。由于无法从浏览器检查`Alt-Svc`头部和实时HTTP/3握手(CORS隐藏跨源头部,且浏览器无法强制建立冷QUIC连接),因此你输入的域名会被发送到一个小的开源后端 (https://github.com/mxinden-bot/savearoundtrip/tree/main/check-service) ,该后端仅执行这两个检查。不会存储任何内容。
实时HTTP/3握手使用quic-go (https://github.com/quic-go/quic-go) 执行。
## 一次往返的成本
一次往返是向服务器发送一条消息并返回的过程,受光速限制:在城市内大约5-20毫秒,跨国家40-80毫秒,跨洋或通过移动网络通常为150毫秒或更长时间(Cloudflare Radar (https://radar.cloudflare.com/quality) 有实时数据)。这种延迟在用户感知层面很重要:低于约100毫秒时,交互感觉即时;超过这个阈值,就会感觉在等待(Nielsen Norman Group (https://www.nngroup.com/articles/response-times-3-important-limits/))。
## 被浪费的一次往返
`Alt-Svc` (RFC 7838 (https://www.rfc-editor.org/rfc/rfc7838)) 是一个HTTP响应头部。要读取它,客户端必须完成一次请求,这意味着它**已经**打开了TCP连接,完成了TLS握手,并使用了HTTP/1.1或HTTP/2。直到这时它才得知“顺便说一下,我也支持HTTP/3”。HTTP/3的升级发生在**下一次**连接上。
#### 仅通过Alt-Svc HTTP头部宣告HTTP/3
```
sequenceDiagram
participant C as 客户端
participant D as DNS
participant S as 你的服务器
Note over C,S: 第一次连接
C->>D: 查询 A / AAAA
D-->>C: IP地址
C->>S: TCP SYN
S-->>C: SYN-ACK
C->>S: TLS ClientHello
S-->>C: TLS ServerHello, Finished
C->>S: HTTP/2 请求
S-->>C: 响应 + Alt-Svc: h3
Note over C,S: 直到此时客户端才知道你支持HTTP/3
Note over C,S: 第二次连接
C->>S: QUIC + HTTP/3 握手
S-->>C: 已连接 (HTTP/3)
```
仅在第二次连接上使用HTTP/3。
而**HTTPS记录** (RFC 9460 (https://www.rfc-editor.org/rfc/rfc9460)) 携带相同的“我支持HTTP/3”信号,但位于DNS中。客户端在进行原本就要执行的名称解析时读取它,**在**打开任何连接**之前**。因此,它可以在第一次连接时就使用QUIC/HTTP/3,而无需先进行一次HTTP/1或HTTP/2连接专门用来发现此信息。
#### 在HTTPS DNS记录中宣告HTTP/3
```
sequenceDiagram
participant C as 客户端
participant D as DNS
participant S as 你的服务器
Note over C,S: 第一次连接
C->>D: 查询 HTTPS 记录
D-->>C: alpn=h3 + IP提示 (+ ECH)
C->>S: QUIC + HTTP/3 握手
S-->>C: 已连接 (HTTP/3)
C->>S: HTTP/3 请求
S-->>C: 响应
```
实时使用HTTP/3,就在第一次连接上。
## 为什么HTTPS记录绝对更好
HTTPS资源记录 (RFC 9460 (https://www.rfc-editor.org/rfc/rfc9460), 2023年11月) 将客户端打开最佳连接所需的一切都整合进了它已经在获取的DNS应答中。具体来说:
### 1 · 在发送第一个字节前发现HTTP/3
`alpn` SvcParam 列出端点支持的ALPN (https://www.rfc-editor.org/rfc/rfc7301) 协议ID,例如 `h3`(HTTP/3 (https://www.rfc-editor.org/rfc/rfc9114))和 `h2`。由于它在名称解析期间到达,客户端可以在**第一次**连接时就选择QUIC,而不是在之前的HTTP/1或HTTP/2连接之后才发现h3。
### 2 · ECH:加密客户端问候(只有DNS能传递)
`ech` SvcParam 承载端点的 `ECHConfigList` 公钥 (RFC 9849 (https://www.rfc-editor.org/rfc/rfc9849.html))。ECH 加密 TLS ClientHello,包括 SNI 服务器名称,因此网络观察者无法看到你正在访问哪个网站。这是一个HTTP头部无法解决的**先有鸡还是先有蛋**问题:你需要**在**发送第一个 ClientHello **之前**获取公钥,而那时恰好没有任何连接存在。只有带外信道(即DNS中的HTTPS记录)才能引导 ECH。没有HTTPS RR,就没有ECH。
### 3 · IP提示:更早开始连接
Happy Eyeballs v3 (https://datatracker.ietf.org/doc/draft-ietf-happy-happyeyeballs-v3/) 已经并行发出 A、AAAA 和 HTTPS 查询。HTTPS 应答中的 `ipv4hint` 和 `ipv6hint` 在其答案先于 A/AAAA 记录到达时,为其提供候选地址以便开始连接,而不必等待 A/AAAA 记录。A/AAAA 记录最终仍会到达并取代提示;提示只是防止首次连接尝试因尚未返回的查询而停滞。`Alt-Svc` 没有等效功能。
### 4 · 单一权威来源,合理缓存
可达性信息位于 DNS 中,并具有常规的 TTL,而不是分散在每个源站的 HTTP 头部缓存中,后者面临 `max-age` 两难:设置过长则客户端使用过时的备选方案,设置过短则客户端比预期更频繁地回退到旧协议。浏览器本来就要进行 DNS 查询;这仅仅让那次查询承载了答案。
| 能力 | Alt-Svc HTTP 头部 (RFC 7838) | HTTPS RR (RFC 9460) |
| :--- | :--- | :--- |
| 何时获知? | 完成一次完整连接后 | 在 DNS 解析期间 |
| 首次连接即支持 h3 | 否 | 是 |
| IP 提示 | 不适用 | ipv4hint / ipv6hint |
| ECH 密钥 | 不可能 | ech 参数 |
| 真实来源 | HTTP 头部 + 脆弱缓存 | DNS,带有 TTL |
## 来自真实浏览器
Firefox Nightly由 Firefox 自身通过 Mozilla 公开的GLAM (https://glam.telemetry.mozilla.org/) 遥测数据测量。
浏览器可以通过**两种**方式获知服务器支持HTTP/3:通过 `Alt-Svc` HTTP 响应头部(仅在已经连接后才能看到),或通过 **HTTPS DNS 记录**(连接前可见)。因此每个连接分为四组之一:
- **两者皆无**:未宣告 HTTP/3。
- **仅 Alt-Svc**:已宣告,但仅在头部中,因此首次连接无法使用。
- **仅 HTTPS 记录**:在 DNS 中宣告,因此首次连接可直接使用 HTTP/3。
- **两者皆有**:在 DNS 和头部中均宣告。
### HTTP/3 发现,按数字统计
已测量连接的份额,Firefox Nightly。这四组覆盖所有连接,合计 100%。右侧两组拥有可用的 HTTPS 记录;**仅 Alt-Svc** 正是记录可以填补的缺口。
### 随时间变化趋势
每个柱状条代表一个 Nightly 构建版本,分为四组(100%)。仅 Firefox Nightly。
## 发布一个(仅需一行)
一个宣告 h3 并带有地址提示的 ServiceMode HTTPS 记录:
```
; 区域文件 (BIND 样式)
example.com. 3600 IN HTTPS 1 . alpn="h3,h2" ipv4hint=203.0.113.10 ipv6hint=2001:db8::10
```
从左到右解读:
- `example.com.` 你发布记录所用的名称;末尾的句点表示完全限定。
- `3600` TTL:解析器可以缓存该记录的秒数。
- `IN` DNS 类别(Internet),与所有网络记录相同。
- `HTTPS` 记录类型 (RFC 9460)。
- `1` 优先级。`1` 或更高表示 ServiceMode(该记录携带参数);`0` 表示 AliasMode,仅指向另一个目标。
- `.` 目标主机。`.` 表示所有者名称本身,此处为 `example.com`。
- `alpn="h3,h2"` 服务器支持的协议,最佳者优先:`h3` 是 HTTP/3,`h2` 是 HTTP/2。
- `ipv4hint` / `ipv6hint` 客户端可立即开始连接的地址,与此同时也进行 A/AAAA 查询。
大多数托管 DNS 提供商(Cloudflare、Route 53 等)直接公开 HTTPS 记录类型。请使用检查器 (https://savearoundtrip.com/#check) 验证你的配置。
## HTTPS 记录在实际中携带的内容
Firefox Nightly在 Firefox 看到 HTTPS 记录的那些连接中,其记录携带各项功能的份额。
来源:Firefox Nightly,通过 GLAM (https://glam.telemetry.mozilla.org/fog/probe/netwerk_happy_eyeballs_https_rr_features/explore) 。基于每个连接的估计自 GLAM 的直方图重建,因此为近似值。
## FAQ
### 我的 CDN 自动发布这个吗?
有些会。例如 Cloudflare 会自动为已代理的区域提供带有 `alpn="h3"` 的 HTTPS 记录。其他 CDN 则留给你自行处理。最快的方法是使用上面的检查域名功能 (https://savearoundtrip.com/#check)。
### HTTPS 记录会破坏旧客户端吗?
不会。不理解 HTTPS 记录的客户端会忽略它,并回退到普通的 A/AAAA 查询(以及你之前发送的 `Alt-Svc` 头部)。发布此记录是严格增量的。
### 重复访问怎么办?
更好:一旦客户端曾与你通过 HTTP/3 通信,重复访问可以在 **0-RTT** 中恢复 QUIC 连接,将首次请求直接发出,无需任何握手往返。而且 HTTPS 记录本身会像任何 DNS 应答一样在其 TTL 内被缓存,因此重复访问通常也无需再次查询。
### 哪些浏览器使用 HTTPS 记录来连接 HTTP/3?
所有主流引擎都支持并默认启用:Chrome (https://chromestatus.com/feature/5154357283651584)、Firefox (https://bugzilla.mozilla.org/show_bug.cgi?id=1721132) 和 Safari (https://mailarchive.ietf.org/arch/msg/dnsop/ldaCto09yaOuSXM92HgJhGqmPJw/)。
### 我应该移除 `Alt-Svc` 头部吗?
不。请继续发送它,作为未获取到 HTTPS 记录的情况(如旧客户端、不传递此记录的解析器或网络)的降级方案。放置好记录后,读取它的浏览器会从 DNS 获知 HTTP/3,而不再需要花费一次往返来发现它。
相似文章
搭建自己的DoH(基于HTTPS的DNS)服务
一篇关于搭建自己的基于HTTPS的DNS(DoH)服务的指南,通过加密DNS查询来提升隐私和安全性。
DNSGlobe – 用 Rust 编写的 TUI 工具,监控 DNS 在全球的传播情况
DNSGlobe 是一款用 Rust 编写的终端应用,可并行查询全球 34 个 DNS 解析器,在世界地图上检查并显示传播状态,并提供持续监控的观察模式。
大规模AI工具发现:只需DNS
本文提出ToolDNS,一个将语义工具发现改造到DNS基础设施上的框架,实现了可扩展的O(log N)解析,并在包含超过33,000个跨多种协议的真实世界工具的基准测试中,将搜索空间减少了95.26%。
Show HN: 运行第二个公共ODoH中继
Numa v0.14 将ODoH客户端和中继整合在一个Rust二进制文件中,无需账户即可实现匿名DNS;本文介绍了其设计以及部署第二个公共ODoH中继的过程。
利用 QUIC 反向散射推断超大规模部署配置
研究人员通过网络望远镜收集的 QUIC 反向散射,推断 Google、Meta 与 Cloudflare 服务器的重传配置,在 QUIC 强调隐私的设计下仍能揭示部署细节。