在过去的几个月里,我写了很多有关 HTTP/2 的文章,也做过好几场相关分享。我在向大家介绍 HTTP/2 的过程中,有一些问题经常会被问到。例如要部署 HTTP/2 一定要先升级到 HTTPS 么?升级到 HTTP/2 之后,不支持 HTTP/2 的浏览器还能正常访问么?本文重点介绍 HTTP/2 的协商机制,明白了服务端和客户端如何协商出最终使用的 HTTP 协议版本,这两个问题就迎刃而解了。 HTTP Upgrade为了更方便地部署新协议,HTTP/1.1 引入了 Upgrade 机制,它使得客户端和服务端之间可以借助已有的 HTTP 语法升级到其它协议。这个机制在 RFC7230 的「 6.7 Upgrade 」这一节中有详细描述。 要发起 HTTP/1.1 协议升级,客户端必须在请求头部中指定这两个字段: 客户端通过 如果服务端不同意升级或者不支持 可以看到,HTTP Upgrade 响应的状态码是 如果大家之前使用过 WebSocket,应该已经对 HTTP Upgrade 机制有所了解。下面是建立 WebSocket 连接的 HTTP 请求: 这是服务端同意升级的 HTTP 响应: 在这之后,客户端和服务端之间就可以使用 WebSocket 协议进行双向数据通讯,跟 HTTP/1.1 没关系了。可以看到,WebSocket 连接的建立就是典型的 HTTP Upgrade 机制。 显然,这个机制也可以用做 HTTP/1.1 到 HTTP/2 的协议升级。例如: 在 HTTP Upgrade 机制中,HTTP/2 的协议名称是 如果服务端支持 HTTP/2,那就可以回应 以下是通过 HTTP Upgrade 机制将 HTTP/1.1 升级到 HTTP/2 的 Wireshark 抓包(两张图可以对照来看):
根据 HTTP/2 协议中的描述,额外补充几点:
HTTP Upgrade 机制本身没什么问题,但很容易受网络中间环节影响。例如不能正确处理 ALPN 扩展HTTP/2 协议本身并没有要求它必须基于 HTTPS(TLS)部署,但是出于以下三个原因,实际使用中,HTTP/2 和 HTTPS 几乎都是捆绑在一起:
如果前面两个原因还不足以说服你,最后这个绝对有说服力,除非你的 HTTP/2 服务只打算给自己客户端用。 下面介绍在 HTTPS 中,浏览器和服务端之间怎样协商是否使用 HTTP/2。 基于 HTTPS 的协议协商非常简单,多了 TLS 之后,双方必须等到成功建立 TLS 连接之后才能发送应用数据。而要建立 TLS 连接,本来就要进行 CipherSuite 等参数的协商。引入 HTTP/2 之后,需要做的只是在原本的协商机制中把对 HTTP 协议的协商加进去。 Google 在 SPDY 协议中开发了一个名为 NPN(Next Protocol Negotiation,下一代协议协商)的 TLS 扩展。随着 SPDY 被 HTTP/2 取代,NPN 也被官方修订为 ALPN(Application Layer Protocol Negotiation,应用层协议协商)。二者的目标和实现原理基本一致,这里只介绍后者。如图:
可以看到,客户端在建立 TLS 连接的 Client Hello 握手中,通过 ALPN 扩展列出了自己支持的各种应用层协议。其中,HTTP/2 协议名称是
如果服务端支持 HTTP/2,在 Server Hello 中指定 ALPN 的结果为 并不是所有 HTTP/2 客户端都支持 ALPN,理论上建立 TLS 连接后,依然可以再通过 HTTP Upgrade 进行协议升级,只是这样会额外引入一次往返。 看到这里,相信你一定可以很好地回答本文开头提出的问题。 HTTP/2 需要基于 HTTPS 部署是当前主流浏览器的要求。如果你的 HTTP/2 服务要支持浏览器访问,那就必须基于 HTTPS 部署;如果只给自己客户端用,可以不部署 HTTPS( 这个页面 列举了很多支持 支持 HTTP/2 的 Web Server 基本都支持 HTTP/1.1。这样,即使浏览器不支持 HTTP/2,双方也可以协商出可用的 HTTP 版本,没有兼容性问题。如下表:
当然,本文讨论的是通用情况。对于自己实现的客户端和服务端,如果打算使用 HTTP/2 ClearText,由于 HTTP Upgrade 协商会增加一次往返,可以要求双方必须支持 HTTP/2,直接发送 HTTP/2 数据,不走协商。 本文链接: https://imququ.com/post/protocol-negotiation-in-http2.html , 参与评论 。 | |||||||||||||||
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|