HTTP/3 Alpn? 为什么网站开启了HTTP3浏览器却是用HTTP/2访问?
Nginx1.25 开始开始支持HTTP/3, 当我使用最新的Chrome(116.0.0.0)访问网站,并非每次都是用HTTP/3,很多次访问同一网站还是采用HTTP/2,就如下图,是5分钟内先后两次的访问记录。
这里就引出一个问题,客户端这里专指浏览器是怎么知道要访问的网站采用的HTTP1.1、HTTP/2还是HTTP/3?
一、ALPN(Application-Layer Protocol Negotiation)应用层协议
ALPN 是一个概念,目的是客户端与服务端协商应用层协议,采用HTTP1.1还是HTTP/2当然也包含已经过期的SPDY。
1.为什么需要做协议协商?
道理很简单客户端访问服务器之前,并不知道服务器采用何种HTTP版本或者支持那些版本。必须通过一种方式来确定客户端到底采用那种方式传输数据。
这个问题产生于HTTP/2诞生,草案阶段有个名叫SPDY的协议,采用NPN方式。随着HTTP/2正式发布,最终主流采用了 TLS ALPN Application-Layer Protocol Negotiation Extension。无论何种方式目的只有一个:尽量少的通信情况下协商好客户端与服务器的通信方式。
2.协商协议的进化
NPN(Transport Layer Security (TLS) Next Protocol Negotiation Extension)
这是一种HTTP/2发布前的SPDY协议使用的方案,这个方案与当前主流的TLS ALPN最相似,不同的是服务端端需要发送支持的协议列表到客户端。协议最终没有发布,只有4个草案。Next Protocol Extension。
The ALPN HTTP Header Field(HTTP 头字段协商)
除了在TLS握手阶段做协议协商,还有一种采用HTTP头的ALPN。与TLS NPN/ALPN不同的是,这种方式依赖HTTPUpgrade完成后续的协议升级。而且网络中不能使用代理,道理也好理解,代理不能打开HTTP包检查头信息。这种方式也没有成为过主流。更多参照The ALPN HTTP Header Field, rfc7639。下面是个头协商的案例:
http header demo CONNECT www.example.com HTTP/1.1
Host: www.example.com
ALPN: h2, http%2F1.1Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension(TLS APLN Extension)
这是当前主流的协议协商方式,包括curl,chrome等主流客户端,nginx等主流服务器都采用这个方式。
从下面这个trace信息,我们能看到客户端列出 h2 http1.1 交给服务器来选择,服务器最终采用server accepted to use h2
HTTP/2通信。相对于头协商不需要upgrade本次就能采用协商好的协议通信。http tls handshake demo * Trying 172.17.0.1:443...
* TCP_NODELAY set
* Connected to notes.icool.io (172.17.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=notes.icool.io
* start date: Aug 27 05:59:58 2023 GMT
* expire date: Nov 25 05:59:57 2023 GMT
* subjectAltName: host "notes.icool.io" matched cert's "notes.icool.io"
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x560ce197c270)
> HEAD / HTTP/2
> Host: notes.icool.io
> user-agent: curl/7.68.0
> accept: */*
二、HTTP/3是怎么协商协议的?
HTTP/3与HTTP/1.1、HTTP/2不同,h3采用quic协议传输层是UDP。协议协商与HTTP/2面对的问题更大复杂。因为采用TLS APLN Extension完全不能解决问题,这里的原因也不难理解。
* Trying 172.17.0.1:443...
* TCP_NODELAY set
* Connected to notes.icool.io (172.17.0.1) port 443 (#0)
* ALPN, offering h3
* ALPN, offering h2
* ALPN, offering http/1.1
假如协商过程是上面那样,就会产生一个问题:真这样握手完,然后呢?没有然后了,这个TCP连接没有用了,看起来浪费一次TCP连接,浪费一次TLS握手。
所以看起来我们已知的协商方式,看起来都不是完美方案。虽然都是不是完美方案,但依旧可以从上面的的方案选择一个看起来代价比较小的方案。HTTP 头字段协商,不同的是HTTP/3采用替代服务通告方式来通告客户端支持的协议,甚至可以可以指定不同的端口号。
1. HTTP Alternative Services(HTTP变更服务)
这是一个在HTTP标准库的头信息,具体格式如下
|
|
当第一次收到 Alt-Svc信息后,浏览器会在一段时间内保留这个信息,下次再次访问的时候直接按照通告内容直接使用HTTP/3 访问了。
2. ALPN还能用吗?
HTTP/3 协议RFC9114 3.1实际上并没有限制ALPN,Alt-Svc并没有完全解决需要首先建立h2连接的问题,同样的ALPN也可以采用这个方式,只是主流浏览器不支持而已。
3. 有什么更好的方案吗?
是的,SVCB 。
SVCB是一个与SRV类似的DNS记录,用来标识支持的协议类型服务端口号等信息。但这个依旧处在开发阶段,
Cloudflare已经支持增加这个记录了,更多信息可以参考 https://blog.cloudflare.com/speeding-up-https-and-http-3-negotiation-with-dns/
|
三、One more thing
1. 测试网站是否支持HTTP/3
2. 测试浏览器是否支持HTTP/3
参考
- SPDY
- Transport Layer Security (TLS) Next Protocol Negotiation Extension
- The ALPN HTTP Header Field, rfc7639
- Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension, rfc7301
- Speeding up HTTPS and HTTP/3 negotiation with… DNS
- Service binding and parameter specification via the DNS (DNS SVCB and HTTPS RRs)