HTTP/2本身并不强制使用SSL/TLS,和HTTP/1.1一样,兼容“http”、“https”的两种URL模式,支持以下两种标识(具体可以看这里):
h2(over TLS),建立在TLS之上的HTTP/2.0,HTTPS模式。
h2c(over TCP),建立在明文TCP之上的HTTP/2.0,HTTP模式。
Protocol Negotiation
如果Client只支持HTTP/1.1,或者Server只支持HTTP/1.1,或者Server只支持h2c,那么Client和Server如何选择合适的协议呢?
那么我们来看一下这Client和Server是如何进行协议协商的。
h2c
针对h2c的协商机制,Client使用了HTTP/1.1的Upgrade(rfc7230#section-6.7)机制,发起了HTTP/1.1的协议升级,Upgrade字段指定了希望升级到的协议和版本号,比如下面这段:
GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
如果Server不支持Upgrade列出的协议,可以直接以HTTP/1.1方式直接响应,比如下面这段:
HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html
...
如果Server支持该协议,必须响应101的状态码,并且在Upgrade空行响应结束之后,可以以新的格式响应请求,比如说HTTP/2.0二进制帧的格式。
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
[ HTTP/2 connection ...
h2协商
由于h2是依赖SSL/TLS的,基于h2的协议协商则依赖于ALPN(Application Layer Protocol Negotiation,应用层协议协商)。也就是在TLS握手阶段,通信双方原本就要进行加密套件等的协商,ALPN作为起拓展字段加入握手协商过程中,对通信不会增添性能影响。具体协商过程如下:
在TLS握手过程中,Client在Client Hello中指定拓展参数ALPN Protocol,即希望升级到的协议列表。
Server收到Client Hello,从展参数ALPN Protocol列表里选择支持的协议。在Server Hello中,回复拓展参数ALPN Protocol,值为选择的协议。
至此就完成了协议协商,双方按照协商的协议进行通信。
下面是针对TLSv1.2的Wireshark抓包图:
总结
尽管HTTP/2.0支持h2c模式,但是可能是考虑到安全问题,基本上主流的浏览器都要求HTTP/2.0部署在SSL/TLS上,所以现在HTTP2.0基本都是基于h2标识,基于HTTPS模式部署。
参考链接
rfc7230 Upgrade
rfc7540