3. 启动 HTTP/2 (Starting HTTP/2)
HTTP/2 连接是在 TCP 连接 ([TCP]) 之上运行的应用层协议. 客户端是 TCP 连接的发起方.
HTTP/2 使用与 HTTP/1.1 相同的 "http" 和 "https" URI schemes. HTTP/2 也共享相同的默认端口号: "http" URIs 使用 80, "https" URIs 使用 443. 因此, 处理目标资源 URI 请求的实现, 例如处理 "http://example.org/foo" 或 "https://example.com/bar" 的实现, 需要首先发现上游服务器 (客户端希望建立连接的直接对等端) 是否支持 HTTP/2.
确定 HTTP/2 支持的方式在 "http" 和 "https" URIs 中不同. "http" URIs 的发现过程见 Section 3.2. "https" URIs 的发现过程见 Section 3.3.
3.1 HTTP/2 版本标识 (HTTP/2 Version Identification)
本文档定义的协议有两个标识符.
-
字符串 "h2" 标识使用传输层安全 (Transport Layer Security, TLS) [TLS12] 的 HTTP/2 协议. 该标识符用于 TLS 应用层协议协商 (application-layer protocol negotiation, ALPN) 扩展 [TLS-ALPN] 字段, 也用于任何需要标识 HTTP/2 over TLS 的位置.
"h2" 字符串会被序列化为 ALPN protocol identifier 中的双八位字节序列: 0x68, 0x32.
-
字符串 "h2c" 标识在明文 TCP 上运行 HTTP/2 的协议. 该标识符用于 HTTP/1.1 Upgrade header field, 也用于任何需要标识 HTTP/2 over TCP 的位置.
"h2c" 字符串从 ALPN 标识符空间中保留, 但描述的是不使用 TLS 的协议.
协商得到 "h2" 或 "h2c" 意味着使用本文档描述的传输, 安全, 分帧和消息语义.
3.2 为 "http" URIs 启动 HTTP/2 (Starting HTTP/2 for "http" URIs)
客户端在没有预先知道下一跳是否支持 HTTP/2 的情况下, 若要为 "http" URI 发出请求, 会使用 HTTP Upgrade 机制 ([RFC7230] 的 Section 6.7). 客户端通过发出一个 HTTP/1.1 请求来完成这一点, 该请求包含一个带有 "h2c" token 的 Upgrade header field. 这样的 HTTP/1.1 请求必须 (MUST) 恰好包含一个 HTTP2-Settings (Section 3.2.1) header field.
例如:
GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
包含 payload body 的请求必须 (MUST) 在客户端能够发送 HTTP/2 frames 之前完整发送. 这意味着大型请求可能会阻塞该连接的使用, 直到它被完全发送.
如果初始请求与后续请求并发很重要, 可以使用 OPTIONS request 执行到 HTTP/2 的升级, 代价是增加一次往返.
不支持 HTTP/2 的服务器可以像 Upgrade header field 不存在一样响应该请求:
HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html
...
服务器必须 (MUST) 忽略 Upgrade header field 中的 "h2" token. 出现 "h2" token 意味着 HTTP/2 over TLS, 而这应按 Section 3.3 所述进行协商.
支持 HTTP/2 的服务器会用 101 (Switching Protocols) 响应接受升级. 在终止 101 响应的空行之后, 服务器可以开始发送 HTTP/2 frames. 这些帧必须 (MUST) 包含对发起升级请求的响应.
例如:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
[ HTTP/2 connection ...
服务器发送的第一个 HTTP/2 frame 必须 (MUST) 是由 SETTINGS frame (Section 6.5) 构成的服务器 connection preface (Section 3.5). 收到 101 响应后, 客户端必须 (MUST) 发送 connection preface (Section 3.5), 其中包含一个 SETTINGS frame.
升级前发送的 HTTP/1.1 请求会被分配流标识符 (stream identifier) 1 (see Section 5.1.1), 并使用默认优先级值 (Section 5.3.5). 由于该请求已经作为 HTTP/1.1 请求完成, 因此从客户端到服务器方向看, stream 1 隐式处于 "half-closed" 状态 (see Section 5.1). 开始 HTTP/2 连接后, stream 1 用于响应.
3.2.1 HTTP2-Settings Header Field
从 HTTP/1.1 升级到 HTTP/2 的请求必须 (MUST) 恰好包含一个 "HTTP2-Settings" header field. HTTP2-Settings header field 是一个连接专用 (connection-specific) header field, 其中包含管理 HTTP/2 连接的参数, 这些参数是在预期服务器接受升级请求的情况下提供的.
HTTP2-Settings = token68
如果该 header field 不存在, 或者存在多个该字段, 服务器绝不能 (MUST NOT) 将连接升级到 HTTP/2. 服务器绝不能 (MUST NOT) 发送此 header field.
HTTP2-Settings header field 的内容是 SETTINGS frame (Section 6.5) 的 payload, 编码为 base64url 字符串 (即 [RFC4648] Section 5 中描述的 URL 和文件名安全 Base64 编码, 并省略任何尾随的 "=" 字符). "token68" 的 ABNF [RFC5234] 产生式定义见 [RFC7235] 的 Section 2.1.
由于升级只打算应用于当前直接连接, 发送 HTTP2-Settings header field 的客户端还必须 (MUST) 在 Connection header field 中将 "HTTP2-Settings" 作为 connection option 发送, 以防止它被转发 (see [RFC7230] 的 Section 6.1).
服务器会像处理任何其他 SETTINGS frame 一样解码并解释这些值. 不需要对这些 settings 进行显式确认 (Section 6.5.3), 因为 101 响应充当了隐式确认. 在升级请求中提供这些值, 让客户端有机会在从服务器接收任何帧之前提供参数.
3.3 为 "https" URIs 启动 HTTP/2 (Starting HTTP/2 for "https" URIs)
向 "https" URI 发出请求的客户端使用带有应用层协议协商 (ALPN) 扩展 [TLS-ALPN] 的 TLS [TLS12].
HTTP/2 over TLS 使用 "h2" protocol identifier. 客户端绝不能 (MUST NOT) 发送 "h2c" protocol identifier, 服务器也绝不能 (MUST NOT) 选择它; "h2c" protocol identifier 描述的是不使用 TLS 的协议.
一旦 TLS 协商完成, 客户端和服务器都必须 (MUST) 发送 connection preface (Section 3.5).
3.4 使用先验知识启动 HTTP/2 (Starting HTTP/2 with Prior Knowledge)
客户端可以通过其他方式获知某个特定服务器支持 HTTP/2. 例如, [ALT-SVC] 描述了一种通告此能力的机制.
客户端必须 (MUST) 发送 connection preface (Section 3.5), 然后可以 (MAY) 立即向这样的服务器发送 HTTP/2 frames; 服务器可以通过 connection preface 的存在来识别这些连接. 这只影响在明文 TCP 上建立 HTTP/2 连接; 支持 HTTP/2 over TLS 的实现必须 (MUST) 使用 TLS [TLS-ALPN] 中的协议协商.
同样, 服务器必须 (MUST) 发送 connection preface (Section 3.5).
如果没有额外信息, 先前支持 HTTP/2 并不能强有力地表明某个给定服务器未来连接仍会支持 HTTP/2. 例如, 服务器配置可能改变, 集群服务器中不同实例的配置可能不同, 网络条件也可能发生变化.
3.5 HTTP/2 Connection Preface
在 HTTP/2 中, 每个端点都需要发送 connection preface, 作为对所用协议的最终确认, 并建立 HTTP/2 连接的初始 settings. 客户端和服务器分别发送不同的 connection preface.
客户端 connection preface 以 24 个八位字节 (octets) 的序列开始, 用十六进制表示为:
0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
也就是说, connection preface 以字符串 "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" 开始. 该序列后必须 (MUST) 跟随一个 SETTINGS frame (Section 6.5), 该帧可以 (MAY) 为空. 客户端在收到 101 (Switching Protocols) 响应 (表示升级成功) 后立即发送 client connection preface, 或者将其作为 TLS 连接中的第一批应用数据八位字节发送. 如果基于服务器支持该协议的先验知识来启动 HTTP/2 连接, client connection preface 会在连接建立时发送.
Note: 选择 client connection preface 的目的, 是让相当大比例的 HTTP/1.1 或 HTTP/1.0 服务器和中间设备不会尝试处理后续帧. 请注意, 这并未解决 [TALKING] 中提出的问题.
服务器 connection preface 由一个可能为空的 SETTINGS frame (Section 6.5) 组成, 该帧必须 (MUST) 是服务器在 HTTP/2 连接中发送的第一个帧.
作为 connection preface 的一部分从对等端收到的 SETTINGS frames, 必须 (MUST) 在发送 connection preface 之后予以确认 (see Section 6.5.3).
为了避免不必要的延迟, 允许客户端在发送 client connection preface 后立即向服务器发送其他帧, 而不必等待接收 server connection preface. 但需要注意的是, server connection preface 中的 SETTINGS frame 可能包含一些参数, 这些参数必然会改变客户端应如何与服务器通信. 收到 SETTINGS frame 后, 客户端应遵守所建立的任何参数. 在某些配置中, 服务器可能在客户端发送其他帧之前传输 SETTINGS, 从而提供避免这一问题的机会.
客户端和服务器必须 (MUST) 将无效的 connection preface 视为类型为 PROTOCOL_ERROR 的连接错误 (connection error) (Section 5.4.1). 在这种情况下可以 (MAY) 省略 GOAWAY frame (Section 6.8), 因为无效 preface 表明对等端未使用 HTTP/2.