启用 HTTP/2

HTTP/2 连接是一个运行在 TCP 连接之上的应用层协议。客户端是 TCP 连接的发起者。

HTTP/2 保持了 HTTP/1.1 的风格,使用相同的“http”和“https”资源标识符(URI)。并使用相同的默认端口号:“http”使用 80 端口,“https”使用 443 端口。因此,要实现对目标资源的 URI 请求处理,如 http://example.org/foo 或者 https://example.com/bar,需要先知道上游服务器(当前客户端希望建立连接的对等端)是否支持 HTTP/2。

“http”和“https”支持 HTTP/2 的手段有所不同。“http”支持 HTTP/2 的方法在 3.2 节详述,而“https”支持 HTTP/2 的方法在 3.3 节详述。

HTTP/2 版本标识符

本文档中所定义的协议有两个标识符。

  • 字符串“h2”标识了使用传输安全层(TLS)的协议。该标识符用于 TLS 应用层协议协商(ALPN)扩展(TLS-ALPN)字段,在任何 TLS 之上的 HTTP 2 都会被该标识符标记。 “h2”字符串在 ALPN 协议标识中被序列化成两个八进制序列:0x68, 0x32。

  • 字符串“h2c”标识了 HTTP 2 运行在明文 TCP 中。该标识符用于 HTTP 1.1 Upgrade 报头字段中,在任何 TCP 之上的 HTTP 2 都会被该标识符标记。

使用“h2”或“h2c”表明使用本协议中定义的传输、安全、帧及语义化消息。

在“http”中启用 HTTP/2

客户端在无法预知服务端是否支持 HTTP/2 的情况下使用 HTTP 升级机制(参考 RFC2730 章节 6.7)发起“http”请求。客户端通过发送 HTTP/1.1 请求,包含 Upgrade 报头字段,并以“h2c”标识符填充。这样的 HTTP/1.1 请求必须(MUST)有且仅有一个 HTTP2-Settings 报头字段。

例如:

GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>

在客户端发送 HTTP 2 帧之前,包含主体内容(Payload)的请求必须(MUST)被完整的发送。这意味着一个较大的请求将会阻塞连接,直到它被完全发送完毕。

如果初始请求与后续请求的并发非常重要,OPTIONS 请求可以用于升级至 HTTP 2 ,这样仅需额外增加一次往返通信的成本。

不支持 HTTP 2 的服务器可以视 Upgrade 报头字段不存在,进行如下响应:

HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html

服务器必须(MUST)忽略 Upgrade 报头字段中的“h2”标识。“h2”标识意味着基于 TLS 的 HTTP/2,应该参考 3.3 节进行协商。

支持 HTTP 2 的服务器接受了升级请求,并以状态码 101(转换协议)进行响应。在 101 空内容响应终止后,服务器可以开始发送 HTTP 2 帧。这些帧必须(MUST)包括一个升级请求对应的响应。

例如:

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c

[ HTTP/2 connection ...

由服务器发送的第一个 HTTP/2 帧必须(MUST)是一个由 SETTINGS 帧(参考章节 6.5)组成的服务器连接序言(Connection Preface)(参考 3.5 章)。根据接收的 101 响应,客户端必须(MUST)发送一个同样包含 SETTINGS 帧的连接序言(Connection Preface)(参考章节 3.5)。

在升级之前所发送的 HTTP 1.1 请求,将被分配一个流标识符 “1”(参考章节 5.1.1),其优先级为默认级别(参考章节 5.3.5)。流 “1” 从 HTTP/1.1 请求完成后,是一个从客户端至服务器的隐性“半关闭”的流(参考章节 5.1)。在开始 HTTP/2 连接后,流 “1” 被用于响应。

HTTP2-Settings 报文头

一个 HTTP/1.1 请求升级至 HTTP/2,必须(MUST)包含有且仅有一个 HTTP2-Settings 报头字段。HTTP2-Settings 报头字段是一个特定于连接的报头字段,其中的参数用于管理 HTTP/2 连接,在服务器接收升级请求时预先提供的。

HTTP2-Settings    = token68

如果没有提供 HTTP2-Settings 报文头,或者提供了超过一个该报文头,服务器禁止(MUST NOT)升级该连接至 HTTP/2。服务器也禁止(MUST NOT)发送这个报文头。

HTTP2-Settings 报文头中的内容,是一个以 Base64 编码的 SETTINGS 帧的主题内容(Payload)(即:URL 和安全文件名的 Base64 描述(RFC4648)的第 5 章,任何结尾的‘=’都将被忽略)。token68 的 ABNF(RFC5234)产物在 RFC7235 有所定义。

由于升级(Upgrade)只应用于直接连接,发送 HTTP2-Settings 的客户端必须(MUST)将 HTTP2-Settings 作为连接选项,包含在 Connection 报文头中,以防止它被转发(参考 RFC7230 章节 6.1)。

服务器解码并解释这些值,并将其看做其他 SETTINGS 帧。由于 101 响应作为了隐式确认,所以没必要显式确认这些设置(参考章节 6.5.3)。在升级请求中提供这些值,使得一个客户端有机会在接收服务器发送任何帧之前提供参数信息。

“https”中启用 HTTP/2

一个发起“https”请求的客户端,需要用到 TLS(TLS1.2) 和应用层协议协商(ALPN) 扩展(TLS-ALPN)。

TLS 之上的 HTTP/2 使用“h2”作为协议标识符。客户端一定不能(MUST NOT)发送“h2c”协议标识符,服务器也一定不能(MUST NOT)选择“h2c”标识符使用。“h2c”协议标识符描述了不适用 TLS 的协议。

一旦 TLS 协商完成,客户端和服务器都必须(MUST)发送一个连接序言(Connection Preface)。

先验下启用 HTTP/2

客户端可以通过其他方式判断服务器是否支持 HTTP 2。例如 ALT-SVC,它描述了一种机制使得 HTTP 具有广播能力。

客户端必须(MUST)发送连接序言(Connection Preface,参考章节 3.5),然后可以(MAY)立即发送 HTTP/2 帧给服务器。服务端可以通过已存在的连接序言识别出这个连接。这只对基于明文 TCP 的 HTTP/2 连接建立有影响,TLS 之上的 HTTP 2 必须(MUST)使用 TLS 协议协商(TLS-ALPN)。

同样的,服务器必须(MUST) 发送连接序言(参考章节 3.5)。

如果没有其他信息,对 HTTP/2 之前的支持并不代表着指定服务器一定会在之后的连接中支持 HTTP/2。比如,服务器配置有可能改变,或者服务器集群中不同的实例配置有差异,亦或者网络状况的变化。

HTTP/2 连接序言

在 HTTP/2 中,每个终端都需要发送一个连接序言作为协议的最终确认以及 HTTP/2 的连接初始设置。客户端和服务器均需要发送一个不同的连接序言。

客户端连接序言以 24 个字节序列开始,以十六进制表示为:

0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a

也就是说,连接序言以字符串 PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n 开头。这个序列后必须(MUST)跟着一个 SETTINGS 帧(参考章节 6.5),其可以(MAY)为空。客户端收到 101 (协议转换)响应后,立刻发送客户端连接序言。或者作为 TLS 连接的第一个应用数据字节。如果在语言验证服务器支持 HTTP 2 的情况下启用 HTTP 2 连接,客户端连接序言在连接建立后发送。

注意:客户端连接序言是用来让大部分 HTTP 1.1 或 HTTP 1.0 服务端及中介端不试图进一步处理帧。注意这并不能解决【TALKING】中提到的问题。

服务器连接序言包含一个可能是空的 SETTINGS 帧(参考章节 6.5),它必须在 HTTP/2 连接中首个发送。

从一个节点接收到的连接序言中所包含的 SETTINGS 帧必须在连接序言发送后被确认(参考章节 6.5.3)。

为了避免不必要的延迟,允许客户端在发送客户端连接序言之后立即发送其他额外的帧,不需要等待收到服务器端连接序言。不过,值得注意的是,服务端连接序言 SETTINGS 帧可能包含一些关于期望客户端如何与服务器端通信的必须修改的参数。在收到这些 SETTINGS 帧后,客户端应当遵守所有设置的参数。在有些配置中,服务器可能在客户端发送其他额外帧之前传输 SETTINGS,以提供一个避免这些问题的机会。

客户端和服务器必须(MUST)将一个非法的连接序言当做一个 PROTOCOL_ERROR 类型的连接错误(Connection error,参考章节 5.4.1)。在这个案例中,当一个节点不支持 HTTP 2 而出现非法序言时,GOAWAY 帧(参考章节 6.8)可以(MAY)被省略。