在上一篇文章《 【HTTP 2】HTTP/2 协议概述(HTTP/2 Protocol Overview) 》中,简单介绍了 HTTP 2 规范的文档结构以及约定和术语。
本文变对 HTTP 2 规范的第一部分进行介绍,来说明如何发起一个 HTTP 2 连接。
HTTP 2 连接是一个运行在 TCP 连接之上的应用层协议。客户端是 TCP 连接的发起者。
HTTP 2 保持了 HTTP 1.1 的风格,同样使用“http”和“https”作为 URI 的开始。并且共享相同的默认端口号:“http”使用 80 端口,“https”使用 443 端口。这意味着,相关实现要处理针对目标资源的请求,比如 http://example.org/foo 或者 https://example.com/bar,需要先知道上游服务器(该客户端当前希望建立的连接)是否支持 HTTP 2。
“http”和“https”支持 HTTP 2 的手段有所不同。“http”支持 HTTP 2 的方法在 3.2 节 详述,而“https”支持 HTTP 2 的方法在 3.3 节 详述。
本文档中所定义的协议有两个标识符。
字符串“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 升级机制。客户端通过发送 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: <base64urlencodingofHTTP/2 SETTINGSpayload>
在客户端发送 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 SwitchingProtocols Connection: Upgrade Upgrade: h2c [ HTTP/2 connection ...
由服务器发送的第一个 HTTP 2 帧必须(MUST)是一个服务器连接序言(Connection Preface)(参考 3.5 章),并且包含一个 SETTINGS 帧(参考章节 6.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” 被用于响应。
一个 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”请求的客户端,需要用到 TLS( TLS1.2 ) 和应用层协议协商(ALPN) 扩展(TLS-ALPN)。
TLS 之上的 HTTP 2 使用“h2”作为协议标识符。客户端一定不能(MUST NOT)发送“h2c”协议标识符,服务器也一定不能(MUST NOT)选择“h2c”标识符使用。“h2c”协议标识符描述了不适用 TLS 的协议。
一旦 TLS 协商完成,客户端和服务器都必须(MUST)发送一个连接序言(Connection preface)。
客户端可以通过其他方式判断服务器是否支持 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 的连接初始设置。客户端和服务器均需要发送一个不同的连接序言。
客户端连接序言以 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)被省略。
本文以 CC BY-NC-SA 3.0 CN 协议共享,转载、共享及二次创作时请保留原文出处及链接,请勿用于商业用途。