HTTP/2 协议规范

  • 简介
  • HTTP2 协议概述
  • 开始HTTP2
    • 1 HTTP2 版本标识符
    • 2 http URIs
      • 21 HTTP2-Settings 头部域
    • 3 https URIs
    • 4 先前知识
    • 5 连接前言
  • HTTP 帧
    • 1 帧格式
    • 2 帧大小
    • 3 头部压缩和解压缩
  • 流和复用
    • 1 流状态
      • 11 流标识符
      • 12 流的并发性
    • 2 流量控制
      • 21 流量控制原理
      • 22 流量控制的适当使用
    • 3 流的优先级
      • 31 流的依赖关系
      • 32 依赖权重
      • 33 重新排序Reprioritization
      • 34 优先级状态管理
      • 35 默认的优先级
    • 4 错误处理
      • 41 连接错误处理
      • 42 流错误处理
      • 43 连接终止
    • 5 HTTP2 扩展
  • 帧定义
    • 1 DATA
    • 2 HEADERS
    • 3 PRIORITY
    • 4 RST_STREAM
    • 5 SETTINGS
      • 51 SETTINGS 格式
      • 52 SETTINGS参数定义
      • 53 Settings 同步
    • 6 PUSH_PROMISE
    • 7 PING
    • 8 GOAWAY
    • 9 WINDOW_UPDATE
      • 91 流量控制窗口
      • 92 初始化流量控制窗口
      • 93 减少流窗口大小
    • 10 CONTINUATION
  • 错误码
  • HTTP 报文交换
    • 1 HTTP 请求响应 交换
      • 11 从HTTP2升级
      • 12 HTTP头部域
        • 121 伪头部域
        • 122 连接特定头部域
        • 123 请求伪头部域
        • 124 响应伪头部域
        • 125 压缩 Cookie头域
        • 126 格式错误的请求和响应
      • 13 例子
      • 14 HTTP2中请求可靠机制
    • 2 服务器推送
      • 21 推送请求
      • 22 推送响应
    • 3 CONNECT 方法
  • 附加HTTP要求注意事项
    • 1 连接管理
      • 11 连接复用
      • 12 421状态码
    • 2 TLS功能
  • Appendix A TLS12 加密套件黑名单

【英文原文对应 RFC7540】

1. 简介

通过引入标题字段压缩并允许在同一连接上进行多个并发交换,HTTP/2可以更有效地使用网络资源,并减少对延迟的感知。 它还介绍了从服务器向客户端主动提供表示的情况。 此规范是HTTP/1.1消息语法的替代,但不会过时。 HTTP的现有语义保持不变。

超文本传输​​协议(HTTP)是一个非常成功的协议。但是,HTTP/1.1使用底层传输的方式([RFC7230],第6部分)有几个特性会对当今的应用程序性能产生负面影响。特别是,

HTTP/1.0在给定的TCP连接上一次只允许一个请求。 
HTTP/1.1添加了请求流水线,但是这只能部分解决请求并发性,并且仍然受到头部阻塞的影响。

因此,需要发出很多请求的HTTP/1.0和HTTP/1.1客户端使用多个连接到服务器,以实现并发性,从而减少延迟。此外,

HTTP标头字段通常是重复的和冗长的,

导致不必要的网络流量以及导致初始TCP [TCP]拥塞窗口快速填充。如果在新的TCP连接上发出多个请求,这可能会导致延迟过大。

HTTP/2通过定义HTTP的语义到底层连接的优化映射来解决这些问题。 具体来说,
* 它允许在同一连接上交织请求和响应消息,并对HTTP头字段使用高效编码。
* 它还可以优先处理请求,让更重要的请求更快完成,进一步提高性能。对网络更友好,可以使用更少的TCP连接, 更好地利用可用网络容量。
* 最后,HTTP/2还可以通过使用二进制消息帧来更有效地处理消息。

2. HTTP/2 协议概述

HTTP/2为HTTP语义提供了优化传输。 HTTP/2支持HTTP/1.1的所有核心功能,但旨在以多种方式提高效率

每种帧类型都有不同的用途。例如,

HEADERS和DATA帧构成HTTP请求和响应的基础(第8.1节);
其他帧类型(如SETTINGS,WINDOW_UPDATE和PUSH_PROMISE)用于支持其他HTTP/2功能。

通过让每个HTTP请求/响应交换与其自己的流相关联来实现请求的多路复用(第5节)。流量控制优先级确保可以有效使用多路复用流。

流量控制(5.2节)有助于确保只有接收机可以使用的数据才能被传输。
确定优先级(第5.3节)确保有限的资源可以首先引导到最重要的流。 

HTTP/2增加了一种新的交互模式服务器可以将响应推送给客户端(见第8.2节)。服务器推送允许服务器将数据推测性地发送到服务器预计客户端将需要的客户端,从而针对潜在的延迟增益进行一些网络使用的交换。服务器通过综合请求来完成此操作,并将其作为PUSH_PROMISE帧发送。服务器然后能够在单独的流上发送对合成请求的响应。

由于连接中使用的HTTP头字段可能包含大量冗余数据,因此包含它们的帧将被压缩(见第4.3节)。这在常见情况下对请求大小具有特别有利的影响,允许将许多请求压缩成一个分组。

3. 开始HTTP/2

3.1 HTTP/2 版本标识符

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

字符串“h2”标识HTTP/2使用传输层安全性(TLS)[TLS12]的协议。 此标识符用于TLS应用层协议协商(ALPN)扩展[TLS-ALPN]字段以及识别TLS上的HTTP/2的任何地方。 “h2”字符串被串行化为一个ALPN协议标识符,作为两个八位字节序列:0x68,0x32

字符串“h2c”标识在明文TCP上运行HTTP/2的协议。 该标识符用于HTTP/1.1升级头字段和任何标识HTTP/2 TCP的地方。 “h2c”字符串是从ALPN标识符空间中保留的,但描述了不使用TLS的协议。 谈判“h2”或“h2c”意味着使用本文档中描述的传输,安全,成帧和消息语义。

3.2 “http” URIs

在事先不知道HTTP/2的支持情况,使用HTTP升级机制客户端通过使用包含具有“h2c”标记的升级标题字段的HTTP/1.1请求来这样做。 这样一个HTTP/1.1请求必须包含一个HTTP2-Settings标题字段。

GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: 

不支持HTTP/2的服务器可以响应该请求,就好像升级标题字段不存在一样:

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

支持HTTP/2的服务器接受使用101(交换协议)响应的升级。 在终止101响应的空行之后,服务器可以开始发送HTTP/2帧。这些帧必须包含对启动升级的请求的响应。

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

[ HTTP/2 connection ...

服务器发送的第一个HTTP/2帧必须是一个服务器连接前置(第3.5节),包含一个SETTINGS帧(6.5节)。一旦收到101响应,客户端必须发送一个连接前言(3.5节),其中包括一个SETTINGS帧。在升级之前发送的HTTP/1.1请求的默认优先级值(见第5.3.5节)被分配了1的流标识符(见第5.1.1节)。由于请求是作为HTTP/1.1请求完成的,所以流1从客户端向服务器隐含“半关闭”(请参见第5.1节)。在开始HTTP/2连接之后,流1用于响应。

3.2.1 HTTP2-Settings 头部域

一个从HTTP/1.1升级到HTTP/2的请求必须包含一个“HTTP2-Settings”标题字段。

HTTP2-Settings标头字段是一个特定于连接的标头字段,其中包含管理HTTP/2连接的参数,这是在服务器接受升级请求的前提下提供的。
如果此标题字段不存在或者存在多个标题字段,则服务器不得将连接升级到HTTP/2。 服务器不能发送这个头域。 HTTP2-Settings标头字段的内容是SETTINGS帧的有效载荷(6.5节),编码为base64url字符串(即[RFC4648]的第5节中描述的URL和文件名安全的Base64编码)尾部’=’字符省略)。 “token68”的ABNF [RFC5234]生产在[RFC7235]的第2.1节中定义。
由于升级只适用于直接连接,发送HTTP2-Settings标头字段的客户端务必在Connection标头字段中发送“HTTP2-Settings”作为连接选项,以防止它被转发 (参见第6.1节[RFC7230])。

服务器将解码和解释这些值,就像其他任何SETTINGS帧一样。显式确认这些设置(第6.5.3节)不是必需的,因为101响应用作隐式确认。在升级请求中提供这些值使客户有机会在从服务器接收任何帧之前提供参数。

3.3 “https” URIs

TLS上的HTTP/2使用“h2”协议标识符。

3.4 先前知识

客户可以通过其他方式了解到特定的服务器支持HTTP/2。 例如,[ALT-SVC]描述了一种广告此功能的机制。 客户端必须发送连接前言(connection preface)(第3.5节),然后可以立即发送HTTP/2帧到这样的服务器; 服务器可以通过连接前言来识别这些连接。 这只影响通过明文TCP建立HTTP/2连接; 通过TLS支持HTTP/2的实现必须使用TLS [TLS-ALPN]中的协议协商。 同样,服务器必须发送连接前言(第3.5节)。 如果没有附加信息,事先对HTTP/2的支持并不是一个强有力的信号,即给定的服务器将支持HTTP/2用于将来的连接。 例如,可以更改服务器配置,使群集服务器中的实例之间的配置不同,或者更改网络条件。

3.5 连接前言

在HTTP/2中,每个端点都需要发送一个连接前言作为正在使用的协议的最终确认,并建立HTTP/2连接的初始设置。客户端和服务器都发送不同的连接前言。客户端连接前言以24个八比特组序列开头,十六进制表示法是:

0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a

也就是说,连接前言以字符串“PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n”开头。
这个序列后面必须紧跟一个设置帧,它可能是空的。

客户端在接收到101(交换协议)响应(指示成功升级)或作为TLS连接的第一个应用数据八位字节时立即发送客户端连接前缀。

如果在事先知道服务器支持该协议的情况下启动HTTP/2连接,则在建立连接时发送客户端连接前缀。

注意:选择客户端连接前言是为了让大部分HTTP/1.1或HTTP/1.0服务器和中间服务器不会尝试处理更多的帧。请注意,这并没有解决[TALKING]中提出的问题。

服务器连接前言包含一个可能为空的SETTINGS帧(第6.5节),必须是服务器在HTTP/2连接中发送的第一帧。发送连接前言后,必须确认从对等方接收到的作为连接前缀一部分的设置帧(参见第6.5.3节)。

为了避免不必要的延迟,客户端可以在发送客户端连接前言后立即向服务器发送额外的帧,而不必等待接收服务器连接前言。
然而,需要注意的是,服务器连接前置设置框架可能包含参数,这些参数必然会改变客户端与服务器的通信方式。 在收到设置框架后,客户需要遵守已建立的任何参数。 在某些配置中,服务器可能会在客户端发送其他帧之前传输设置,从而为避免此问题提供机会。
客户端和服务器必须将一个无效的连接前缀视为PROTOCOL_ERROR类型的连接错误
GOAWAY框架(6.8节)在这种情况下可以省略,因为无效前言表明对等方没有使用HTTP/2。

4 HTTP 帧

一旦建立了HTTP/2连接,端点就可以开始交换帧。

4.1 帧格式

所有帧以一个固定的9个八位组首标开始,后跟一个可变长度的有效载荷。帧头的字段定义为:

+-----------------------------------------------+
|                 Length (24)                   |
+---------------+---------------+---------------+
|    Type (8)   |   Flags (8)   |
+-+-------------+---------------+-------------------------------+
|R|                    Stream Identifier (31)                   |
+=+=============================================================+
| Frame Payload (0...) ...
+---------------------------------------------------------------+

              Figure 1: Frame Layout
  • Length:帧有效载荷的长度,表示为无符号的24位整数。除非接收方为SETTINGS_MAX_FRAME_SIZE设置了较大的值,否则不得发送大于2 ^ 14(16,384)的值。帧头的9个八位字节不包含在该值中。

  • Type:帧的8位类型。帧类型决定帧的格式和语义。实现必须忽略并丢弃任何类型未知的帧。

  • Flags:为帧类型专用的布尔标志保留的8位字段。标志被分配特定于指定帧类型的语义。没有为特定帧类型定义语义的标志务必被忽略,并且在发送时务必保持未设置(0x0)。

  • R:保留的1位字段。该位的语义是未定义的,并且该位必须在发送时保持未设置(0x0),并且在接收时必须忽略。

  • Stream Identifier:流标识符(见第5.1.1节)表示为一个无符号的31位整数。值0x0保留给与整个连接相关联的帧,而不是单个流。

帧有效载荷的结构和内容完全取决于帧类型。

4.2 帧大小

帧有效载荷的大小受到接收机在SETTINGS_MAX_FRAME_SIZE设置中通告的最大大小的限制。
该设置可以为包含2 ^ 14(16,384)和2 ^ 24-1(16,777,215)个八位字节之间的任何值。所有的实现都必须能够接收和最小化长度为2 ^ 14个八位字节的帧,再加上9个八位字节的帧头(4.1节)。描述帧大小时不包括帧头的大小

注意:某些帧类型(如PING(6.7节))会对允许的有效载荷数据量施加额外的限制。

如果帧超过了在SETTINGS_MAX_FRAME_SIZE中定义的大小,超过了为帧类型定义的任何限制,或者太小而不能包含强制帧数据,则端点必须发送FRAME_SIZE_ERROR的错误代码。帧中的帧大小错误可能会改变整个连接的状态,必须将其视为连接错误(见第5.4.1节)。这包括任何携带标题块(第4.3节)(即HEADERS,PUSH_PROMISE和CONTINUATION),SETTINGS以及流标识符为0的任何帧的帧。端点不必使用帧中的所有可用空间。通过使用小于允许的最大尺寸的框架可以提高响应能力。发送较大的帧可能会导致发送对时间敏感的帧(如RST_STREAM,WINDOW_UPDATE或PRIORITY)的延迟,如果传输较大的帧,则会影响性能。

4.3 头部压缩和解压缩

头部列表是零个或多个头部域的集合。当通过连接传输时,使用HTTP头压缩[COMPRESSION]将头部列表序列化为头部块。然后将序列化头部块分成一个或多个八位位组序列,称为头部块分段,并在HEADERS(6.2节),PUSH_PROMISE(6.6节)或CONTINUATION(6.10节)帧的有效载荷内传送。 Cookie头域[COOKIE]被HTTP映射专门处理(参见第8.1.2.5节)。接收端点通过连接其片段重新组装头部块,然后解压缩该块以重构头部列表。

完整的头部块包含以下任一项:
- 单个HEADERS或PUSH_PROMISE帧,并设置END_HEADERS标志 或
- 清除了END_HEADERS标志的HEADERS或PUSH_PROMISE帧和一个或多个CONTINUATION帧,其中最后一个CONTINUATION帧设置了END_HEADERS标志。

头部压缩是有状态的。一个压缩上下文和一个解压缩上下文用于整个连接。头块中的解码错误必须被视为COMPRESSION_ERROR类型的连接错误(第5.4.1节)。

头部块分段只能作为HEADERSPUSH_PROMISECONTINUATION帧的有效载荷发送,因为这些帧携带的数据可以修改接收器维护的压缩上下文。接收HEADERSPUSH_PROMISECONTINUATION帧的端点需要重新组合头块并执行解压缩,即使要丢弃这些帧也是如此。如果接收方不解压头部块,接收方必须终止连接,并带有COMPRESSION_ERROR类型的连接错误(第5.4.1节)。

5 流和复用

“流”是在HTTP/2连接中在客户端和服务器之间交换的独立双向帧序列。
流有几个重要特征:
- 一个HTTP/2连接可以包含多个同时打开的流,并且可以从多个流中交叉帧。
- 流可以单独建立和使用,也可以由客户端或服务器共享。
- 流可以由任一端点关闭。
- 帧在流上发送的顺序非常重要。 收件人按收到的顺序处理框架。 特别是,HEADERS和DATA帧的顺序在语义上很重要。
- 流由一个整数标识。 流标识符由启动流的端点分配给流。

5.1 流状态

HTTP/2 协议规范_第1张图片

请注意,此图显示了流状态转换以及仅影响这些转换的帧和标志。 在这方面,CONTINUATION帧不会导致状态转换; 它们实际上是它们遵循的HEADERSPUSH_PROMISE的一部分。 出于状态转换的目的,END_STREAM标志作为单独的事件处理到承载它的帧; 具有END_STREAM标志设置的HEADERS帧可以导致两个状态转换。 两个端点都有一个流动状态的主观视图,当帧在运输过程中可能会有所不同。 端点不协调创建流; 它们是由任一端点单方面创建的。 在发送RST_STREAM之后,状态不匹配的负面影响仅限于“关闭”状态,在关闭后帧可能会被接收一段时间。

数据流具有以下状态:

idle:

所有的流都以 idle状态开始。

以下转换在此状态下有效:

  • 发送或接收HEADERS帧会导致流成为“打开”。 流标识符的选择如5.1.1节所述。 相同的HEADERS帧也可以使流立即变成“半封闭”。
  • 在另一个流上发送PUSH_PROMISE帧将保留为以后使用而标识的空闲流。 保留流的流状态转换为“reserved (local)”。
  • 在另一个流上接收PUSH_PROMISE帧会保留一个空闲流,以供以后使用。 保留流的流状态转换为“reserved (remote)”。
  • 请注意,PUSH_PROMISE帧不在空闲流上发送,而是在Promised Stream ID字段中引用新保留的流。 在这种状态下,在流上接收除HEADERSPRIORITY之外的任何帧必须被视为类型为PROTOCOL_ERROR的连接错误(见第5.4.1节)。

reserved (local):

处于“reserved (local)”状态的流是通过发送PUSH_PROMISE帧来承诺的流。 PUSH_PROMISE帧通过将流与远程对等端发起的开放流关联来保留空闲流(参见第8.2节)。

在这种状态下,只有以下转换是可能的:

  • 端点可以发送HEADERS帧。 这会导致流在“半封闭(远程)”状态下打开。
  • 任一端点都可以发送一个RST_STREAM帧,以使流成为“关闭”。 这将释放流预留。

在此状态下,端点不得发送除HEADERS,RST_STREAM或PRIORITY之外的任何类型的帧。 可以在此状态下接收优先级或WINDOW_UPDATE帧。 在此状态的流上接收除RST_STREAM,PRIORITY或WINDOW_UPDATE以外的任何类型的帧必须视为PROTOCOL_ERROR类型的连接错误(见第5.4.1节)。

reserved (remote):

处于“reserved (remote)”状态的流已被远程对等体保留。

在这种状态下,只有以下转换是可能的:

  • 接收HEADERS帧会导致数据流转换为“half-closed(local)”。
  • 任一端点都可以发送一个RST_STREAM帧,以使流成为“关闭”。 这将释放流预留。

    端点可以在这种状态下发送PRIORITY帧来重新设置保留流的优先级。 在此状态下,端点不得发送除RST_STREAM,WINDOW_UPDATE或PRIORITY以外的任何类型的帧。 在这种状态下,在流上接收除HEADERS,RST_STREAM或PRIORITY以外的任何类型的帧必须被视为类型为PROTOCOL_ERROR的连接错误(见第5.4.1节)。

open:

处于“打开”状态的流可以被两个对等体用来发送任何类型的帧。 在这种状态下,发送对等方遵守广告流级别的流量控制限制(第5.2节)。

在这种状态下,任何一个端点都可以发送一个带有END_STREAM标志的帧,这会导致流转换到“半闭合”状态之一。 发送END_STREAM标志的端点导致流状态变为“半关闭(本地)”; 接收END_STREAM标志的端点将导致流状态变为“半关闭(远程)”。 每个端点都可以从此状态发送一个RST_STREAM帧,使其立即转换为“关闭”。

half-closed (local):

处于“半封闭(本地)”状态的流不能用于发送WINDOW_UPDATE,PRIORITY和RST_STREAM以外的帧。 当接收到包含END_STREAM标志的帧或任一对等体发送RST_STREAM帧时,流将从此状态转换为“关闭”状态。 一个端点可以在这种状态下接收任何类型的帧。 使用WINDOW_UPDATE帧提供流量控制信用是继续接收流量控制帧所必需的。 在这种状态下,接收方可以忽略WINDOW_UPDATE帧,在发送END_STREAM标志的帧之后可能会短时间到达。 在此状态下收到的优先级帧用于重新确定依赖于已识别流的流的优先级。

half-closed (remote):

“半封闭(远程)”的流不再被对等方用来发送帧。 在这种状态下,端点不再需要维护接收器流量控制窗口。 如果端点接收到除WINDOW_UPDATE,PRIORITY或RST_STREAM之外的其他帧,则对于处于此状态的流,它必须响应类型为STREAM_CLOSED的流错误(第5.4.2节)。 “半封闭(远程)”的流可以被端点用来发送任何类型的帧。 在这种状态下,端点会继续观察广告流级别的流量控制限制(第5.2节)。 通过发送一个包含END_STREAM标志的帧或任一对等体发送RST_STREAM帧,流可以从此状态转换为“关闭”状态。

close:

“关闭”状态是终端状态。端点不得在封闭流上发送PRIORITY以外的帧

  • 在接收到RST_STREAM后接收除PRIORITY以外的任何帧的端点必须将其视为类型STREAM_CLOSED的流错误(第5.4.2节)。
  • 类似地,在接收到END_STREAM标志集合的帧后接收任何帧的端点必须将其视为STREAM_CLOSED类型的连接错误(第5.4.1节),除非该帧是允许的,如下所述。
  • WINDOW_UPDATE或RST_STREAM帧可以在包含END_STREAM标志的DATA或HEADERS帧发送后的短时间内在此状态下接收。

在远程节点接收并处理RST_STREAM或带有END_STREAM标志的帧之前,它可能会发送这些类型的帧。终端必须忽略在这种状态下接收到的WINDOW_UPDATE或RST_STREAM帧,虽然终端可以选择处理发送END_STREAM之后到达相当长时间的帧,作为类型为PROTOCOL_ERROR的连接错误(见第5.4.1节)。优先帧可以在封闭流上发送,以优先依赖于封闭流的流。端点应该处理PRIORITY帧,尽管如果流已经从依赖关系树中移除了,它们可以被忽略(见5.3.4节)。如果由于发送RST_STREAM帧而达到此状态,那么接收RST_STREAM的对等方可能已经发送 - 或已排队发送 - 无法撤销的流上的帧。端点必须在发送RST_STREAM帧后忽略它在封闭流上接收到的帧。端点可以选择限制它忽略帧的时间段,并将在此时间后到达的帧视为错误。在发送RST_STREAM之后接收的流量控制帧(即DATA)被计数到连接流量控制窗口。即使这些帧可能被忽略,因为它们是在发送者收到RST_STREAM之前发送的,发送者会认为这些帧是针对流量控制窗口进行计数的。端点在发送RST_STREAM后可能会收到一个PUSH_PROMISE帧。即使关联的流已重置,PUSH_PROMISE也会使流成为“保留”。因此,需要RST_STREAM来关闭不需要的承诺流。

请注意,PRIORITY可以在任何流状态下发送和接收。未知类型的帧被忽略。

5.1.1 流标识符

流用无符号的31位整数标识客户端发起的流必须使用奇数流标识符;那些由服务器发起的必须使用偶数流标识符。连接控制消息使用零(0x0)的流标识符;零流标识符不能用于建立新的流。被升级到HTTP / 2的HTTP / 1.1请求(请参阅第3.2节)以一个流标识符(0x1)响应。升级完成后,流0x1是“半封闭(本地)”到客户端。因此,流0x1不能被从HTTP / 1.1升级的客户端选择为新的流标识符。新建立的流的标识符必须在数字上大于发起端点已经打开或保留的所有流。这将控制使用HEADERS帧打开的流和使用PUSH_PROMISE保留的流。接收到意外流标识符的端点必须响应PROTOCOL_ERROR类型的连接错误(第5.4.1节)。新流标识符的第一次使用隐式地关闭了可能已经由该对等体以低值流标识符发起的“空闲”状态中的所有流。例如,如果客户端在流7上发送HEADERS帧而没有在流5上发送帧,则当流7的第一帧被发送或接收时,流5转换到“闭合”状态。流标识符不能被重用。长时间连接会导致端点耗尽流标识符的可用范围。无法建立新流标识符的客户端可以为新流建立新连接。无法建立新流标识符的服务器可以发送GOAWAY帧,以便强制客户端为新流打开新连接。

5.1.2 流的并发性

对端可以使用SETTINGS框架内的SETTINGS_MAX_CONCURRENT_STREAMS参数来限制并发活动流的数量。最大并发流设置特定于每个端点,并且仅适用于接收设置的对等端。也就是说,客户端指定服务器可以启动的并发流的最大数量,服务器指定客户端可以启动的并发流的最大数量。处于“打开”状态或处于“半封闭”状态的流都计入端点允许打开的最大数据流数。以上三种状态中的任何一种状态下的流都会计入SETTINGS_MAX_CONCURRENT_STREAMS设置中通告的限制。任何一个“保留”状态的流都不计入流限制。端点不得超出其对等设置的限制。接收到HEADERS帧的端点会导致超出其公布的并发流限制,务必将其视为PROTOCOL_ERROR或REFUSED_STREAM类型的流错误(第5.4.2节)。错误代码的选择决定端点是否希望启用自动重试(详见第8.1.4节)。希望将SETTINGS_MAX_CONCURRENT_STREAMS的值减小到低于当前打开流数的值的端点可以关闭超过新值的流或允许流完成。

5.2 流量控制

将流用于多路复用会引起对使用TCP连接的争用,从而导致流被阻塞。 流量控制机制确保同一连接上的流不会相互干扰。 流量控制用于单个流和整个连接。 HTTP/2通过使用WINDOW_UPDATE帧提供流量控制(第6.9节)。

5.2.1 流量控制原理

HTTP/2流量控制旨在允许使用各种流量控制算法,而无需更改协议。 HTTP/2中的流量控制具有以下特征:

  1. 流量控制特定于连接。两种类型的流量控制都位于单跳的端点之间,而不是整个端到端路径。
  2. 流量控制基于WINDOW_UPDATE帧。接收者宣告他们准备在一个流上以及整个连接上接收多少个字节。这是一个以信贷为基础的计划。
  3. 流量控制是由接收器提供的全面控制方向。接收者可以选择为每个流和整个连接设置它想要的任何窗口大小。发送方必须遵守接收方施加的流量控制限制。客户端,服务器和中介都独立地将其流量控制窗口作为接收者进行通告,并遵守发送时由对等方设置的流量控制限制。
  4. 对于新流和整个连接,流量控制窗口的初始值为65,535个八比特组。
  5. 帧类型决定流量控制是否适用于帧。在本文档中指定的帧中,只有数据帧受流量控制;所有其他帧类型不会占用通告的流量控制窗口中的空间。这确保了重要的控制框架不会被流量控制阻塞。
  6. 流量控制不能禁用。
  7. HTTP/2仅定义WINDOW_UPDATE帧的格式和语义(6.9节)。

本文没有规定接收方如何决定何时发送该帧或其发送的值,也没有规定发送方如何选择发送数据包。实现能够选择适合其需求的任何算法。实现还负责管理如何根据优先级发送请求和响应,选择如何避免头部线段阻塞请求以及管理新流的创建。这些算法的选择可以与任何流量控制算法进行交互。

5.2.2 流量控制的适当使用

流量控制被定义为保护在资源限制下运行的端点。例如,代理需要在多个连接之间共享内存,并且可能有一个缓慢的上游连接和一个下游快速连接。流量控制解决了接收方无法在一个流上处理数据,但仍希望继续处理同一连接中的其他流的情况。不需要此功能的部署可以通告最大大小(2 ^ 31-1)的流量控制窗口,并且可以在收到任何数据时通过发送WINDOW_UPDATE帧来维护此窗口。这有效地禁用了该接收器的流量控制。相反,发送者总是受到接收者通告的流量控制窗口的限制。具有受限资源(例如内存)的部署可采用流量控制来限制对等体可消耗的内存量。但是,请注意,如果在不知道带宽延迟产品的情况下启用流量控制,可能会导致可用网络资源使用次最佳(请参阅[RFC7323])。即使充分了解当前的带宽延迟产品,流量控制的实施也很困难。在使用流量控制时,接收器必须及时从TCP接收缓冲区读取数据。如果不这样做,可能会导致关键帧(如WINDOW_UPDATE)未被读取和执行时发生死锁。

5.3 流的优先级

客户端可以通过在打开流的HEADERS帧中包含优先级信息来为新流分配优先级在其他任何时候,PRIORITY帧都可以用来改变流的优先级。

优先化的目的是允许端点表达它在管理并发流时如何选择分配资源。最重要的是,当发送容量有限时,可以使用优先级来选择用于发送帧的流。可以通过将流标记为依赖于其他流的完成来优先化流(见第5.3.1节)。

每个依赖项都分配了一个相对权重(weight),这个权重用于确定分配给依赖于同一个流的流的可用资源的相对比例。显式设置流的优先级被输入到优先级过程。它不保证流相对于任何其他流的任何特定处理或传输顺序。端点不能强制对等体使用优先级以特定顺序处理并发流。因此表示优先权只是一个建议。优先级信息可以从消息中省略。在提供任何显式值之前使用默认值(见第5.3.5节)。

5.3.1 流的依赖关系

每个流可以被赋予对另一个流的显式依赖。包括依赖关系表示优先将资源分配给识别的流而不是依赖流。不依赖于任何其他流的流被赋予0x0的流依赖性。换句话说,不存在的流0形成树的根。依赖于另一个流的流是依赖流。流所依赖的流是父流。对当前不在树中的流(例如处于“空闲”状态的流)的依赖会导致该流被赋予默认优先级(见第5.3.5节)。当分配对另一个流的依赖关系时,该流将添加为父流的新依赖关系。共享相同父级的依赖流不会相对于彼此进行排序。例如,如果流B和C依赖于流A,并且如果流D是依赖于流A创建的,则这会导致依赖顺序为A,其次是B,C和D,顺序无关。

BB

独有的(exclusive)标志允许插入新的依赖关系。独有标志使流成为其父流的唯一依赖,导致其他依赖性依赖于独有流。 在前面的示例中,如果创建的流D对流A具有独有依赖关系,则会导致D成为B和C的依赖关系父级。

HTTP/2 协议规范_第2张图片

在依赖关系树中,依赖关系流只应该被分配资源,如果它所依赖的所有流(父流高达0x0的链)被关闭或者不可能在这些流上取得进展。

流不能依赖于它自己。 一个端点必须将其视为PROTOCOL_ERROR类型的流错误(第5.4.2节)。

5.3.2 依赖权重

所有依赖流都被分配一个介于1和256之间(包括)的整数权重。 与同一父级流应该根据其权重按比例分配资源。 因此,如果流B依赖于权重为4的流A,则流C依赖于权重为12的流A,并且在流A上不能取得进展,流B理想地接收分配给流C的资源的三分之一。

5.3.3 重新排序(Reprioritization)

流优先级使用PRIORITY帧进行更改。 设置依赖性会导致流依赖于已识别的父流。

如果父级重新设置了优先级,则依赖流会随其父级流一起移动。 使用重新优先化流的专用标志设置依赖关系会导致新父流的所有依赖关系依赖于重新优先化的流。 如果一个流依赖于它自己的一个依赖关系,那么先前的依赖流首先被移动以依赖于重新优先化的流的前一个父对象。 移动的依赖关系保持其重量。

例如,考虑一个原始依赖关系树,其中B和C依赖于A,D和E依赖于C,并且F依赖于D.如果A依赖于D,则D取代A.所有其他依赖关系保持不变 同样的,除了F,如果重新排序是独有性的,那么F就会依赖于A.

HTTP/2 协议规范_第3张图片

5.3.4 优先级状态管理

当一个流从依赖关系树中被移除时,它的依赖关系可以被移动成依赖于关闭流的父对象。通过基于其依赖关系的权重按比例分配封闭流的依赖关系的权重来重新计算新依赖关系的权重。

从依赖关系树中移除的流会导致某些优先级信息丢失。资源在具有相同父流的流之间共享,这意味着如果该组中的流关闭或被阻塞,则分配给流的任何剩余容量将被分配给流的直接邻居。但是,如果公共依赖关系从树中删除,那么这些流会与下一个最高级别的流共享资源。

例如,假设流A和B共享一个父节点,并且流C和D都依赖于流A.在流A被移除之前,如果流A和D不能继续,则流C接收所有专用于流A.如果将流A从树中移除,则流A的权重在流C和D之间分配。如果流D仍然无法继续,则这导致流C接收减少的资源比例。对于相同的起始权重,C获得三分之一而非一半的可用资源。

流有可能被关闭,而优先级信息会创建对该流的依赖关系。如果依赖项中标识的流没有关联的优先级信息,则依赖流将被赋予默认优先级(见第5.3.5节)。这可能会创建次优化的优先级,因为可以给予流的优先级与预期不同。

为了避免这些问题,端点应该在流关闭后的一段时间内保持流优先级状态。保留的状态越长,流被分配不正确或默认优先级值的机会越少。

类似地,处于“空闲”状态的流可以被分配优先级或成为其他流的父节点。这允许在依赖关系树中创建分组节点,从而实现更灵活的优先级表达式。空闲流以默认优先级开始(第5.3.5节)。

对未计入SETTINGS_MAX_CONCURRENT_STREAMS设置的限制的流保留优先级信息可能会给端点造成较大的状态负担。因此,保留的优先级状态的数量可能会受到限制。

端点维护的优先级附加状态的数量可能取决于负载;在高负荷下,可以放弃优先化状态以限制资源承诺。在极端情况下,端点甚至可以丢弃活动或保留流的优先级状态。如果应用了限制,端点应该至少保持其SETTINGS_MAX_CONCURRENT_STREAMS设置允许的状态。实现也应该尝试保留优先级树中正在使用的流的状态。

如果它保留了足够的状态来执行此操作,则接收改变封闭流优先级的PRIORITY帧的端点应该改变依赖于它的流的依赖关系。

5.3.5 默认的优先级

所有流最初都被分配给流0x0的非独占(non-exclusive)依赖。 推送流(8.2节)最初取决于它们的相关流。 在这两种情况下,流的默认权重均为16

5.4 错误处理

HTTP/2帧允许出现两类错误:

  • 导致整个连接不可用的错误条件是连接错误
  • 单个流中的错误是流错误

第7节包含错误代码列表。

5.4.1 连接错误处理

连接错误是阻止进一步处理帧层或破坏任何连接状态的任何错误。遇到连接错误的端点应首先发送一个GOAWAY帧(见第6.8节),其中包含从其对等端成功接收到的最后一个流的流标识符。

GOAWAY框架包含一个错误代码,指明连接终止的原因。

发送GOAWAY帧之后,端点必须关闭TCP连接。

GOAWAY可能不会被接收端点可靠接收([RFC7230],第6.6节描述了直接连接关闭如何导致数据丢失)。在出现连接错误的情况下,GOAWAY只会尽力尝试与对等方进行通信,以了解连接终止的原因。终端可以随时结束连接。特别是,端点可能会选择将流错误视为连接错误。如果情况允许,端点应该在结束连接时发送GOAWAY帧。

5.4.2 流错误处理

流错误是与特定流相关的错误,不影响其他流的处理。检测到流错误的端点发送RST_STREAM帧(第6.4节),该帧包含发生错误的流的流标识符。

RST_STREAM帧包含一个指示错误类型的错误代码。

RST_STREAM是端点可以在流上发送的最后一帧。

发送RST_STREAM帧的对等方必须准备好接收任何被远程对等方发送或排队发送的帧。这些帧可以被忽略,除非它们修改连接状态(例如为头压缩(4.3节)或流量控制维护的状态)。通常情况下,端点不应该为任何流发送多个RST_STREAM帧。但是,如果端点在多次往返时间后收到封闭流上的帧,端点可能会发送其他RST_STREAM帧。这种行为被允许处理行为不当的实现。

为避免循环,端点不得发送RST_STREAM来响应RST_STREAM帧。

5.4.3 连接终止

如果TCP连接在流保持“打开”或“半封闭”状态时关闭或重置,则受影响的流不能自动重试 (详见第8.1.4节)。

5.5 HTTP/2 扩展

HTTP/2允许扩展协议。在本节所述的限制内,协议扩展可用于提供附加服务或更改协议的任何方面。扩展仅在单个HTTP/2连接的范围内有效。这适用于本文档中定义的协议元素。这不会影响扩展HTTP的现有选项,例如定义新方法,状态代码或标题字段。允许扩展使用新的帧类型(第4.1节),新的设置(第6.5.2节)或新的错误代码(第7节)。为管理这些扩展点建立了注册管理机构:框架类型(第11.2节),设置(第11.3节)和错误代码(第11.4节)。实现必须忽略所有可扩展协议元素中未知或不支持的值。实现必须丢弃具有未知或不支持类型的帧。这意味着任何这些扩展点都可以被扩展安全地使用,而无需事先安排或协商。然而,出现在标题块中间的扩展帧(4.3节)是不允许的;这些必须被视为类型为PROTOCOL_ERROR的连接错误(第5.4.1节)。可能会改变现有协议组件语义的扩展必须在使用之前进行协商。例如,改变HEADERS帧的布局的扩展只有在对等体给出了可接受的肯定信号之后才能使用。在这种情况下,当修改后的布局生效时,也可能需要进行协调。请注意,将除DATA帧之外的任何帧视为流控制,都是语义上的这种变化,只能通过协商完成。本文件没有规定谈判延期使用的具体方法,但注意到可以为此设置一个设置(第6.5.2节)。如果两个对等设置了一个表示愿意使用该扩展的值,则可以使用该扩展。如果一个设置用于扩展协商,则初始值必须以扩展最初禁用的方式定义。

6 帧定义

该规范定义了多种帧类型,每种帧类型都由唯一的8位类型代码标识 。 每个帧类型在建立和管理整个连接或单个流的连接方面起着独特的作用。 特定帧类型的传输可以改变连接的状态。

6.1 DATA

DATA帧(type= 0x0)传送与流关联的任意长度可变的八位字节序列。 例如,使用一个或多个DATA帧来携带HTTP请求或响应有效载荷。 数据帧可能还包含填充。 可以将填充添加到数据帧以遮蔽消息的大小。 填充是一项安全功能; 见第10.7节。

HTTP/2 协议规范_第4张图片

DATA帧包含以下字段:

  • Pad Length :8位字段,以八位位组为单位,包含帧填充的长度。 该字段是有条件的(如图中的“?”所示),并且只有在设置了PADDED标志时才存在。
  • Data:应用程序数据。数据量是减去存在的其他字段的长度后帧负载的剩余部分。
  • Padding:填充不包含应用语义值的字节。 发送时,填充字节必须设置为零。 接收方没有义务验证填充,但可以将非零填充视为PROTOCOL_ERROR类型的连接错误(第5.4.1节)。

DATA帧定义如下标志:

  • END_STREAM(0x1):若设置,bit 0 指示此帧是端点将为识别的流发送的最后一个帧。 设置该标志会导致数据流进入“半封闭”状态或“关闭”状态(5.1节)。
  • PADDED(0x8):若设置,bit 3 指示 Pad Length字段及其描述的填充符存在。

数据帧必须与流关联。 如果收到的数据帧的流标识符字段为0x0,则接收方必须响应PROTOCOL_ERROR类型的连接错误(第5.4.1节)。

数据帧受流量控制,只能在流处于“打开”或“半封闭(远程)”状态时发送。 整个数据帧有效载荷包含在流量控制中,如果存在的话,包括填充长度和填充字段。 如果接收到的数据流的流未处于“打开”或“半封闭(本地)”状态,则接收方必须响应STREAM_CLOSED类型的流错误(第5.4.2节)。

填充八位字节的总数由填充长度字段的值决定。 如果填充的长度是帧有效载荷的长度或更大,接收者必须将其视为类型为PROTOCOL_ERROR的连接错误(见第5.4.1节)。

注意:通过包含一个值为零的填充长度字段,可以将帧的大小增加一个八位字节。

如下DATA帧在wireshark中所示:
HTTP/2 协议规范_第5张图片

6.2 HEADERS

HEADERS帧(type = 0x1)用于打开一个流(Section 5.1),并且还携带一个头块段。 HEADERS帧可以在”idle”, “reserved (local)”, “open”, 或”half-closed (remote)”状态下在流上发送。

HTTP/2 协议规范_第6张图片

HEADERS帧有效负载具有以下字段:

  • Pad Length (填充长度):8位字段,以八位位组为单位,包含帧填充的长度。 该字段仅在PADDED标志置位时才存在。
  • E :表示流依赖性是唯一的单位标志(参见5.3节)。 该字段仅在设置了PRIORITY标志时才存在。
  • Stream Dependency (数据流相关性):该数据流依赖的流的31位流标识符(见5.3节)。 该字段仅在设置了PRIORITY标志时才存在。
  • Weight (权重):一个无符号的8位整数,表示流的优先级权重(见5.3节)。 将值加1以获得介于1和256之间的权重。此字段仅在设置了PRIORITY标志时出现。
  • Header Block Fragment (头部块片段):标题块的片段(4.3节)。
  • Padding :填充的字节。

HEADERS帧定义如下标志:

  • END_STREAM(0x1):若设置,位0 指示头部块(4.3节)是端点将为识别的流发送的最后一个。 HEADERS帧携带END_STREAM标志,表示流的结束。但是,具有END_STREAM标志设置的HEADERS帧可以跟随在同一个流上的CONTINUATION帧。从逻辑上说,CONTINUATION帧是HEADERS帧的一部分。
  • END_HEADERS(0x4):若设置,位2 指示该帧包含整个头部块(4.3节),并且没有任何CONTINUATION帧。没有END_HEADERS标记集的HEADERS帧必须跟随同一个流的CONTINUATION帧。接收方必须将接收到的任何其他类型的帧或不同流上的帧视为PROTOCOL_ERROR类型的连接错误(第5.4.1节)。
  • PADDED(0x8):若设置,位3 指示Pad Length字段及其描述的填充符存在。
  • PRIORITY(0x20):若设置,位5 指示存在专用标志(E),流依赖性和权重字段;见5.3节。

HEADERS帧的有效载荷包含一个头块段(第4.3节)。一个不适合在HEADERS帧中的头部块在CONTINUATION帧中继续(6.10节)。 HEADERS帧必须与流相关联。如果收到的流标识符字段为0x0的HEADERS帧,收件人必须响应PROTOCOL_ERROR类型的连接错误(第5.4.1节)。如第4.3节所述,HEADERS帧改变连接状态。 HEADERS框架可以包含填充。填充字段和标志与为DATA帧定义的填充字段和标志相同(6.1节)。填充超过头块分段的剩余大小必须被视为PROTOCOL_ERROR。 HEADERS帧中的优先级信息在逻辑上等同于单独的PRIORITY帧,但包含在HEADERS中可避免在创建新流时在流优先级中进行流失的可能性。流之后的HEADERS帧中的优先化字段重新设置流的优先顺序(见第5.3.3节)。

如下HEADERS帧在wireshark中所示:

HTTP/2 协议规范_第7张图片

6.3 PRIORITY

PRIORITY帧(type = 0x2)指定了流发送者建议的优先级(5.3节)。 它可以以任何流状态发送,包括空闲或封闭的流。

HTTP/2 协议规范_第8张图片

PRIORITY帧的有效载荷包含以下字段:

  • E :表示流依赖性是唯一的单比特标志(见5.3节)。
  • Stream Dependency (数据流相关性):该数据流依赖的流的31位流标识符(见5.3节)。
  • Weight (权重):一个无符号的8位整数,表示流的优先级权重(见5.3节)。 将值加1以获得介于1和256之间的权重。

PRIORITY帧不定义任何标志

PRIORITY帧始终标识一个流。如果接收到一个流标识符为0x0的PRIORITY帧,接收方必须响应PROTOCOL_ERROR类型的连接错误(第5.4.1节)。 PRIORITY帧可以在任何状态下的流上发送,尽管它不能在构成单个标题块的连续帧之间发送(见4.3节)。请注意,此帧可能在处理完成或帧发送完成后到达,这会导致它对已识别的流没有任何影响。对于处于“半封闭(远程)”或“关闭”状态的流,此帧只能影响对已识别流及其依赖流的处理;它不会影响该流上的帧传输。 PRIORITY帧可以发送一个处于“空闲”或“关闭”状态的流。这允许通过改变未使用或已关闭的父流的优先级来重新设置一组从属流的优先级。长度不超过5个八位字节的优先帧必须被视为类型为FRAME_SIZE_ERROR的流错误(第5.4.2节)。

如下PRIORITY帧在wireshark中所示:

HTTP/2 协议规范_第9张图片

6.4 RST_STREAM

RST_STREAM帧(类型= 0x3)允许立即终止一个流。 发送RST_STREAM以请求取消流或指示发生了错误情况。

RST_STREAM

RST_STREAM帧包含一个标识错误代码的单个无符号的32位整数(第7节)。错误代码指示流被终止的原因。 RST_STREAM帧不定义任何标志

RST_STREAM帧完全终止参考流并使其进入“关闭”状态。在流上接收到RST_STREAM之后,接收者不得为该流发送额外的帧,但PRIORITY除外。但是,在发送RST_STREAM之后,发送端点务必准备好接收和处理在RST_STREAM到达之前可能已经由对端发送的流上发送的附加帧。

RST_STREAM帧必须与一个流相关联。如果接收到RST_STREAM帧且流标识符为0x0,则接收方必须将其视为PROTOCOL_ERROR类型的连接错误(第5.4.1节)。

RST_STREAM帧不得在“空闲”状态下发送流。如果接收到标识空闲流的RST_STREAM帧,接收者必须将其视为类型为PROTOCOL_ERROR的连接错误(见第5.4.1节)。

长度不是4个八位组的RST_STREAM帧必须被视为FRAME_SIZE_ERROR类型的连接错误(第5.4.1节)。

6.5 SETTINGS

SETTINGS帧(type= 0x4)传达影响端点通信方式的配置参数,例如对对等行为的偏好和约束。 SETTINGS框架也用于确认收到这些参数。 单独地,SETTINGS参数也可以被称为“setting”。

SETTINGS参数不协商;它们描述了接收端使用的发送端的特征。每个对等体可以通告相同参数的不同值。例如,客户端可能会设置较高的初始流量控制窗口,而服务器可能会设置较低的值以节省资源。设置帧必须在连接开始时由两个端点发送,并且可以在连接的整个生命周期内由任一端点在任何其他时间发送。实现必须支持本规范定义的所有参数。设置框中的每个参数都会替换该参数的任何现有值。参数按它们出现的顺序进行处理,并且设置帧的接收器不需要保持除参数当前值以外的任何状态。因此,SETTINGS参数的值是接收器看到的最后一个值。设置参数由接收方确认。为了实现这一点,SETTINGS框架定义了以下标志:

  • ACK (0x1):若设置,位0表示该帧确认接收和应用对等设备帧。 当该位设置时,SETTINGS帧的有效载荷必须为空。 收到一个设置了ACK标志并且长度字段值不为0的SETTINGS帧必须被视为FRAME_SIZE_ERROR类型的连接错误(见第5.4.1节)。

设置帧始终适用于连接,而不是单个流。 设置帧的流标识必须为零(0x0)。 如果一个端点收到一个SETTINGS帧,其流标识符字段不是0x0,那么端点必须响应一个类型为PROTOCOL_ERROR的连接错误(见第5.4.1节)。 SETTINGS框架影响连接状态。 严格形成或不完整的设置帧必须被视为类型为PROTOCOL_ERROR的连接错误(见第5.4.1节)。 长度不是6个字节倍数的SETTINGS帧必须被视为FRAME_SIZE_ERROR类型的连接错误(第5.4.1节)。

6.5.1 SETTINGS 格式

SETTINGS帧的有效载荷由零个或多个参数组成,每个参数由一个无符号的16位设置标识符一个无符号的32位值组成。

HTTP/2 协议规范_第10张图片

如下SETTINGS帧在wireshark中所示:
HTTP/2 协议规范_第11张图片

6.5.2 SETTINGS参数定义

如下参数定义:

  • SETTINGS_HEADER_TABLE_SIZE (0x1):允许发送者以八位字节的形式通知远程端点用于解码头块的头压缩表的最大尺寸。编码器可以通过使用特定于头部块内头部压缩格式的信令来选择等于或小于此值的任何大小(请参见[压缩])。初始值是4,096个八位字节。
  • SETTINGS_ENABLE_PUSH (0x2):此设置可用于禁用服务器推送(第8.2节)。如果一个端点接收到这个参数设置为0的值,它不应该发送一个PUSH_PROMISE帧。一个端点既将这个参数设置为0,并且确认它也必须将PUSH_PROMISE帧的接收视为连接错误(见5.4节)。 1)类型PROTOCOL_ERROR。初始值为1,表示允许服务器推送。除0或1以外的任何值必须视为PROTOCOL_ERROR类型的连接错误(第5.4.1节)。
  • SETTINGS_MAX_CONCURRENT_STREAMS (0x3):表示发件人允许的最大并发流数。这个限制是有方向性的:它适用于发送者允许接收者创建的数据流。最初,这个值没有限制。建议此值不小于100,以免不必要地限制并行性。值为0的SETTINGS_MAX_CONCURRENT_STREAMS不应被视为特殊的端点。零值确实会阻止创建新的流;然而,这也可能发生在活动流所耗尽的任何限制上。服务器应该只在短时间内设置一个零值;如果服务器不希望接受请求,关闭连接更合适。
  • SETTINGS_INITIAL_WINDOW_SIZE (0x4):指示发送者的流级别流控制的初始窗口大小(以八位字节为单位)。初始值是2 ^ 16-1(65,535)个八位组。该设置会影响所有流的窗口大小(请参阅第6.9.2节)。高于最大流量控制窗口大小2 ^ 31-1的值必须视为FLOW_CONTROL_ERROR类型的连接错误(见第5.4.1节)。
  • SETTINGS_MAX_FRAME_SIZE (0x5):指示发送者愿意接收的最大帧有效载荷的大小,以八位字节为单位。初始值是2 ^ 14(16,384)个八位字节。端点通告的值必须在该初始值和最大允许帧大小之间(2 ^ 24-1或16,777,215个八位字节),包括在内。此范围之外的值务必视为PROTOCOL_ERROR类型的连接错误(第5.4.1节)。
  • SETTINGS_MAX_HEADER_LIST_SIZE (0x6):此通报设置以八位字节的形式通知对等方发送方准备接受的标题列表的最大大小。该值基于头字段的未压缩大小,包括名称和八位字节的值的长度,以及每个头字段的开销32个字节。对于任何给定的请求,可能会强制实施一个比所宣传的更低的限制。

此设置的初始值是无限的。接收到带有任何未知或不支持标识符的SETTINGS帧的端点必须忽略该设置。

6.5.3 Settings 同步

SETTINGS中的大部分值受益于或需要了解对等体何时接收并应用更改的参数值。 为了提供这样的同步时间点,其中未设置ACK标志的SETTINGS帧的接收方必须在收到后尽快应用更新的参数。 设置帧中的值必须按照它们出现的顺序进行处理,值之间没有其他帧处理。 不支持的参数必须被忽略。 一旦所有值都被处理完毕,接收者必须立即发出一个设置了ACK标志的SETTINGS帧。 一旦接收到设置了ACK标志的设置帧,改变参数的发送者就可以依靠已经应用的设置。 如果SETTINGS帧的发送者在合理的时间内没有收到确认,它可能会发出SETTINGS_TIMEOUT类型的连接错误(第5.4.1节)。

6.6 PUSH_PROMISE

PUSH_PROMISE帧(type = 0x5)用于在发送者打算启动的流之前通知对端。 PUSH_PROMISE帧包括端点计划创建的流的无符号31位标识符以及为流提供附加上下文的一组头。 第8.2节包含了对PUSH_PROMISE帧使用的全面描述。

HTTP/2 协议规范_第12张图片

如下域:

  • Pad Length(填充长度):8位字段,以八位位组为单位,包含帧填充的长度。 该字段仅在PADDED标志置位时才存在。
  • R:一个保留位。
  • Promised Stream ID:一个无符号的31位整数,用于标识由PUSH_PROMISE保留的流。 承诺流标识符必须是发送方发送的下一个流的有效选择(请参阅第5.1.1节中的“新流标识符”)。
  • Header Block Fragment(头部块片段):包含请求头部字段的头部块片段(部分4.3)。
  • Padding:填充字节。

如下标志:

  • END_HEADERS(0x4):置位时,位2指示该帧包含整个头部块(4.3节),并且没有任何CONTINUATION帧。 没有设置END_HEADERS标志的PUSH_PROMISE帧必须跟着同一个流的CONTINUATION帧。 接收方必须将接收到的任何其他类型的帧或不同流上的帧视为类型为PROTOCOL_ERROR的连接错误(见第5.4.1节)。
  • PADDED(0x8):置位时,位3指示Pad Length字段及其描述的填充符存在。

PUSH_PROMISE帧必须只能在处于“打开”或“半封闭(远程)”状态的对等启动流上发送。 PUSH_PROMISE帧的流标识符指示与其关联的流。如果流标识符字段指定值0x0,则接收方必须响应类型为PROTOCOL_ERROR的连接错误(第5.4.1节)。承诺的流不需要按照承诺的顺序使用。 PUSH_PROMISE仅保留流标识符供以后使用。如果对等端点的SETTINGS_ENABLE_PUSH设置被设置为0,则不应发送PUSH_PROMISE。已设置此设置并已收到确认的端点务必将PUSH_PROMISE帧的接收视为类型为PROTOCOL_ERROR的连接错误(见第5.4.1节) 。 PUSH_PROMISE帧的收件人可以通过将RST_STREAM引用承诺的流标识符返回给PUSH_PROMISE的发送者来选择拒绝承诺的流。 PUSH_PROMISE框架以两种方式修改连接状态。首先,包含一个标题块(4.3节)可能会修改为标题压缩而维护的状态。其次,PUSH_PROMISE还保留一个流供以后使用,导致承诺流进入“保留”状态。发送者不得在流上发送PUSH_PROMISE,除非该流是“打开”或“半关闭(远程)”;发送方必须确保承诺流是新流标识符的有效选择(见第5.1.1节)(也就是说,承诺流必须处于“空闲”状态)。由于PUSH_PROMISE保留流,忽略PUSH_PROMISE帧会导致流状态变得不确定。接收方必须将一个既不是“打开”也不是“半封闭(本地)”的流上的PUSH_PROMISE的接收视为PROTOCOL_ERROR类型的连接错误(第5.4.1节)。但是,在关联流上发送RST_STREAM的端点必须处理在接收和处理RST_STREAM帧之前可能已经创建的PUSH_PROMISE帧。接收方必须将接收到的PUSH_PROMISE作为PROTOCOL_ERROR类型的连接错误(见第5.4.1节)来承诺非法流标识符(第5.1.1节)。请注意,非法流标识符是当前不处于“空闲”状态的流的标识符。 PUSH_PROMISE帧可以包含填充。填充字段和标志与为DATA帧定义的填充字段和标志相同(6.1节)。

如下PUSH_PROMISE帧在wireshark中所示:

HTTP/2 协议规范_第13张图片

6.7 PING

PING帧(type = 0x6)是一种机制,用于测量来自发送方的最小往返时间,以及确定空闲连接是否仍然有效。 PING帧可以从任何端点发送。

HTTP/2 协议规范_第14张图片

除帧头外,PING帧必须在有效载荷中包含8个不透明数据字节。 发送者可以包含它选择的任何值,并以任何方式使用这些八位字节。 不包括ACK标记的PING帧的接收者务必发送一个PING帧,并在响应中设置ACK标志,并使用相同的有效载荷。 PING响应应该被赋予比任何其他帧更高的优先级

PING帧定义了以下标志:

  • ACK(0x1):置位时,位0表示该PING帧是PING响应。 一个端点必须在PING响应中设置这个标志。 一个端点不能响应包含这个标志的PING帧。

PING帧不与任何单独的流关联。 如果接收到的PING帧的流标识符字段值不是0x0,则接收方必须响应PROTOCOL_ERROR类型的连接错误(第5.4.1节)。 接收长度字段值不是8的PING帧必须被视为FRAME_SIZE_ERROR类型的连接错误(第5.4.1节)。

6.8 GOAWAY

GOAWAY帧(类型= 0x7)用于启动连接关闭或发出严重错误状态信号。 GOAWAY允许端点正常停止接受新的流,同时仍然完成对先前建立的流的处理。这可以实现管理操作,例如服务器维护。在开始新流的端点和远程发送GOAWAY帧之间存在固有的竞争条件。为了处理这种情况,GOAWAY包含在此连接中的发送端点上处理或可能处理的最后一个peer-initiated流的流标识符。例如,如果服务器发送GOAWAY帧,则标识的流是由客户端发起的编号最大的流。一旦发送,如果流的标识符高于包含的最后流标识符,则发送方将忽略由接收方发起的流上发送的帧。 GOAWAY帧的接收者不能在连接上打开额外的流,尽管可以为新的流建立新的连接。如果GOAWAY的接收者已经发送了具有比GOAWAY帧更高的流标识符的流的数据,那么这些流不被处理或将不被处理。 GOAWAY帧的接收者可以将这些流视为从未被创建,从而允许这些流稍后在新连接上重试。端点应该总是在关闭连接之前发送一个GOAWAY帧,以便远程节点可以知道流是否已被部分处理。例如,如果HTTP客户端在服务器关闭连接的同时发送POST,则客户端无法知道服务器是否开始处理该POST请求,如果服务器未发送GOAWAY帧来指示它可能具有哪些流采取行动。端点可以选择关闭连接而不发送GOAWAY用于行为不当的同伴。 GOAWAY框架可能不会立即在连接关闭之前;一个GOAWAY的接收器不再使用连接,应该在终止连接之前发送一个GOAWAY帧。

HTTP/2 协议规范_第15张图片

GOAWAY框架适用于连接,而不是特定的流。 一个端点必须将一个带有0x0以外的流标识符的GOAWAY帧视为一个类型为PROTOCOL_ERROR的连接错误(见第5.4.1节)。 GOAWAY帧还包含一个32位错误代码(第7节),其中包含关闭连接的原因。端点可以将不透明数据附加到任何GOAWAY帧的有效载荷。额外的调试数据仅用于诊断目的,并没有语义值。调试信息可能包含安全或隐私敏感数据。记录或以其他方式持久存储的调试数据必须有足够的安全措施以防止未经授权的访问。

如下GOAWAY帧在wireshark中所示:

HTTP/2 协议规范_第16张图片

6.9 WINDOW_UPDATE

WINDOW_UPDATE帧(type = 0x8)用于实现流量控制; 有关概述,请参阅第5.2节。

流量控制在两个层面上运行:在每个单独的流整个连接上。

两种类型的流量控制都是逐跳的,也就是说,只在两个端点之间。 中介机构不会在相关连接之间转发WINDOW_UPDATE帧。 然而,任何接收器对数据传输的节流可能间接导致流量控制信息向原始发送者传播。 流量控制仅适用于被识别为受流量控制影响的帧。 在本文档中定义的帧类型中,仅包含数据帧。 除非接收方无法分配资源来处理帧,否则必须接受并处理不受流量控制限制的帧。 如果接收器无法接受帧,它可能会响应FLOW_CONTROL_ERROR类型的流错误(第5.4.2节)或连接错误(第5.4.1节)。

window_update

WINDOW_UPDATE帧的有效载荷是一个保留位加上一个无符号的31位整数,指出除了现有的流量控制窗口之外,发送者可以传输的八位字节数。流量控制窗口增量的合法范围是1到2 ^ 31-1(2,147,483,647)个八位组。

WINDOW_UPDATE框架没有定义任何标志。

WINDOW_UPDATE帧可以是特定于流或整个连接的。在前一种情况下,帧的流标识符指示受影响的流;在后者中,值“0”表示整个连接是帧的主题。

接收方必须将接收到的流量控制窗口增量为0的WINDOW_UPDATE帧作为PROTOCOL_ERROR类型的流错误(第5.4.2节)处理;连接流量控制窗口上的错误务必视为连接错误(见第5.4.1节)。 WINDOW_UPDATE可以由发送带有END_STREAM标志的帧的对等方发送。这意味着接收器可以在“半关闭(远程)”或“关闭”流上接收WINDOW_UPDATE帧。接收方不得将其视为错误(参见第5.1节)。接收流量控制帧的接收者必须始终考虑其对连接流量控制窗口的影响,除非接收者将其视为连接错误(见第5.4.1节)。即使帧出错,这也是必要的。发送方向流量控制窗口计数帧,但如果接收方不这样做,则发送方和接收方的流量控制窗口可能会不同。长度不超过4个八位字节的WINDOW_UPDATE帧必须被视为FRAME_SIZE_ERROR类型的连接错误(5.4.1节)。

如下WINDOW_UPDATE帧在wireshark中所示:
HTTP/2 协议规范_第17张图片

6.9.1 流量控制窗口

6.9.2 初始化流量控制窗口

6.9.3 减少流窗口大小

6.10 CONTINUATION

CONTINUATION帧(type = 0x9)用于继续一系列头块分片(第4.3节)。 只要前面的帧位于同一个流上,并且是未设置END_HEADERS标志的HEADERS,PUSH_PROMISE或CONTINUATION帧,就可以发送任意数量的CONTINUATION帧。

continuation

CONTINUATION帧有效载荷包含一个头部块片段。

CONTINUATION帧定义了以下标志:

  • END_HEADERS(0x4):置位时,位2表示该帧结束头部块(4.3节)。

如果未设置END_HEADERS位,则该帧必须紧跟着另一个CONTINUATION帧。接收方必须将接收到的任何其他类型的帧或不同流上的帧视为PROTOCOL_ERROR类型的连接错误(第5.4.1节)。

CONTINUATION帧必须与流相关联。如果收到其流标识符字段为0x0的CONTINUATION帧,接收方必须响应PROTOCOL_ERROR类型的连接错误(第5.4.1节)。连续帧必须在前面加上HEADERS,PUSH_PROMISE或CONTINUATION帧,而不要设置END_HEADERS标志。观察违反此规则的收件人必须响应PROTOCOL_ERROR类型的连接错误(第5.4.1节)。

7 错误码

错误代码是32位字段,用于RST_STREAMGOAWAY帧来传达流或连接错误的原因。 错误代码共享一个共同的代码空间。 某些错误代码仅适用于流或整个连接,并且在其他上下文中没有定义的语义。

定义了以下错误代码:

  • NO_ERROR(0x0):相关的条件不是错误的结果。例如,GOAWAY可能包含此代码以指示正常关闭连接。
  • PROTOCOL_ERROR(0x1):端点检测到非特定协议错误。此错误用于更具体的错误代码不可用时。
  • INTERNAL_ERROR(0x2):端点遇到意外的内部错误。
  • FLOW_CONTROL_ERROR(0x3):端点检测到它的对等方违反了流量控制协议。
  • SETTINGS_TIMEOUT(0x4):端点发送了一个SETTINGS帧,但没有及时收到响应。参见6.5.3节(“设置同步”)。
  • STREAM_CLOSED(0x5):流在半封闭后收到一个帧。
  • FRAME_SIZE_ERROR(0x6):端点收到一个无效大小的帧。
  • REFUSED_STREAM(0x7):端点在执行任何应用程序处理之前拒绝流(详情请参见第8.1.4节)。
  • CANCEL(0x8):由端点使用,表示不再需要该流。
  • COMPRESSION_ERROR(0x9):端点无法维护连接的头压缩上下文。
  • CONNECT_ERROR(0xa):响应CONNECT请求建立的连接(第8.3节)被重置或异常关闭。
  • ENHANCE_YOUR_CALM(0xb):端点检测到它的对等体表现出可能产生过度负载的行为。
  • INADEQUATE_SECURITY(0xc):底层传输具有不符合最低安全要求的属性(参见第9.2节)。
  • HTTP_1_1_REQUIRED(0xd):端点要求使用HTTP/1.1而不是HTTP/2。

未知或不支持的错误代码不得触发任何特殊行为。这些可以被实现视为等同于INTERNAL_ERROR。

8 HTTP 报文交换

HTTP/2旨在尽可能与HTTP的当前使用兼容。 这意味着,从应用的角度来看,协议的功能在很大程度上是不变的。 为了达到这个目的,所有的请求和响应语义都被保留下来,尽管传达这些语义的语法已经改变了。 因此,HTTP/1.1语义和内容[RFC7231],条件请求[RFC7232],范围请求[RFC7233],缓存[RFC7234]和认证[RFC7235]的规范和要求适用于HTTP/2。 HTTP/1.1消息语法和路由[RFC7230]的选定部分(如HTTP和HTTPS URI方案)也适用于HTTP/2,但这些协议的这些语义表达式在以下各节中定义。

8.1 HTTP 请求/响应 交换

客户端使用以前未使用的流标识符在新流上发送HTTP请求(第5.1.1节)。服务器在与请求相同的流上发送HTTP响应。

HTTP消息(请求或响应)由以下部分组成:

  1. 仅用于响应,包含信息(1xx)HTTP响应的消息头的零个或多个HEADERS帧(每个HEADERS帧后跟零个或多个CONTINUATION帧)(请参见[RFC7230],第3.2节和[RFC7231]第6.2节),
  2. 包含消息头(见[RFC7230],第3.2节)的一个HEADERS帧(后跟零个或多个CONTINUATION帧),
  3. 包含有效负载体的零个或多个DATA帧(见[RFC7230],第3.3节)和
  4. 可选择的一个HEADERS帧,后跟零个或多个包含尾部的连续帧(如果存在的话)(见[RFC7230],第4.1.2节)。

序列中的最后一个帧带有一个END_STREAM标志,注意带有END_STREAM标志的HEADERS帧可以跟随带有头部块剩余部分的CONTINUATION帧。其他帧(来自任何流)不得出现在HEADERS帧和可能接续的任何CONTINUATION帧之间。 HTTP/2使用数据帧来传送消息有效载荷。

HEADERS帧(和相关的CONTINUATION帧)只能出现在流的开始或结束处。在接收到最终(非信息性)状态代码后接收到未设置END_STREAM标志的HEADERS帧的端点必须将相应的请求或响应视为格式错误(见第8.1.2.6节)。 HTTP请求/响应交换完全消耗单个流。

8.1.1 从HTTP/2升级

HTTP/2取消了对101(交换协议)信息状态码([RFC7231],第6.2.2节)的支持。 101(交换协议)的语义不适用于多路复用协议。 替代协议能够使用HTTP/2用于协商其使用的相同机制(参见第3节)。

8.1.2 HTTP头部域

HTTP标头字段将信息作为一系列键值对携带。 有关已注册HTTP头的列表,请参阅https://www.iana.org/assignments/message-headers中维护的“消息头字段”注册表。 就像在HTTP/1.x中一样,头部字段名称是以不区分大小写的方式进行比较的ASCII字符字符串。 但是,在HTTP/2中编码之前,头部字段名称必须转换为小写字母。包含大写头字段名称的请求或响应必须被视为格式错误(见第8.1.2.6节)。

8.1.2.1 伪头部域

尽管HTTP/1.x使用消息开始行(请参阅[RFC7230],第3.1节)来传达目标URI,请求方法和响应的状态代码,但HTTP/2使用特殊的伪头字段以’:’字符开始(ASCII 0x3a)。伪头字段不是HTTP头字段。

端点不能生成非本文定义的伪头字段。

伪头字段仅在定义它们的上下文中有效。

为请求定义的伪报头字段不能出现在响应中;为响应定义的伪头字段不能出现在请求中。

伪头字段不能出现在预告片中。

端点必须将包含未定义或无效伪头字段的请求或响应视为格式错误(见第8.1.2.6节)。所有伪头字段必须出现在常规头字段之前的头部块中。任何包含伪头域的请求或响应必须被视为格式错误(见第8.1.2.6节)。

8.1.2.2 连接特定头部域

HTTP/2不使用Connection头字段来指示特定于连接的头字段; 在这个协议中,连接特定的元数据是通过其他方式传递的。端点绝不能生成包含特定于连接的头字段的HTTP/2消息;任何包含连接特定报头字段的消息必须被视为格式错误(见第8.1.2.6节)。唯一的例外是TE头字段,它可能存在于HTTP/2请求中;当它是时,它不能包含“trailers”以外的任何值。这意味着将HTTP/1.x消息转换为HTTP/2的中介需要删除由Connection头字段指定的任何头字段以及Connection头字段本身。这样的中介也应该删除其他连接特定的头域,例如Keep-Alive,Proxy-Connection,Transfer-Encoding和Upgrade,即使它们没有被Connection头域指定。注意:HTTP/2有意不支持升级到其他协议。

8.1.2.3 请求伪头部域

定义:

  • :method”伪头字段包含HTTP方法([RFC7231],第4节)。

  • :scheme”伪头字段包含目标URI的方案部分([RFC3986],第3.1节)。 “:scheme”不限于“http”和“https”策划的URI。代理或网关可以转换对非HTTP方案的请求,从而使HTTP可以与非HTTP服务交互。

  • :authority”伪头字段包含目标URI的权威部分([RFC3986],第3.2节)。权威机构绝不能在“http”或“https”方案URI中包含弃用的“userinfo”子组件。

    直接生成HTTP/2请求的客户端应该使用“:authority”伪头字段而不是Host头字段。

  • :path”伪头部字段包括目标URI的路径和查询部分(“路径绝对”生成和可选的’?’字符,后跟“查询”生成(参见RFC3986的第3.3节和第3.4节) ])。

对于“http”或“https”URI,该伪头字段不能为空;“http”或“https “不包含路径组件的URI必须包含’/’的值,这个规则的例外是对不包含路径组件的”http“或”https“URI的OPTIONS请求;它们必须包含一个” :路径“伪头字段值为’*’(见[RFC7230],第5.3.4节)。

除非是CONNECT请求(见第8.3节),否则所有HTTP/2请求必须包含“:method”,“:scheme”和“:path”伪头字段的一个有效值。 忽略强制伪头字段的HTTP请求格式错误(第8.1.2.6节)。 HTTP/2没有定义携带HTTP/1.1请求行中包含的版本标识符的方法。

如下wireshark 所示:

HTTP/2 协议规范_第18张图片

8.1.2.4 响应伪头部域

对于HTTP/2响应,定义了一个包含HTTP状态代码字段的单个“:status”伪头字段(请参见[RFC7231],第6节)。 这个伪头域必须包含在所有的响应中; 否则,响应格式错误(第8.1.2.6节)。 HTTP/2没有定义携带包含在HTTP/1.1状态行中的版本或原因短语的方法。

HTTP/2 协议规范_第19张图片

8.1.2.5 压缩 Cookie头域

Cookie标头字段[COOKIE]使用分号(“;”)分隔cookie对(或“碎屑”)。 这个头域不遵循HTTP中的列表构造规则(参见[RFC7230],第3.2.2节),它可以防止cookie对分成不同的名称 - 值对。 随着单个cookie对的更新,这可以显着降低压缩效率。 为了提供更好的压缩效率,Cookie头字段可以被分割成单独的头字段,每个头字段都带有一个或多个cookie对。 如果解压缩后有多个Cookie头字段,在传递到非HTTP / 2上下文之前,这些字段必须使用0x3B,0x20(ASCII字符串“;”)的双字节定界符连接成单个八位字符串,例如 作为HTTP / 1.1连接或通用HTTP服务器应用程序。 因此,下面两个Cookie头域的列表在语义上是等价的。

cookie: a=b; c=d; e=f
cookie: a=b
cookie: c=d
cookie: e=f

8.1.2.6 格式错误的请求和响应

检测到的格式错误的请求或响应必须被视为类型为PROTOCOL_ERROR的流错误。

8.1.3 例子

HTTP GET请求包括请求头字段和无有效负载体,因此作为单个HEADERS帧进行传输,然后传输包含序列化的请求头字段块的零个或多个CONTINUATION帧。 下面的HEADERS帧同时设置了END_HEADERS和END_STREAM标志; 没有发送CONTINUATION帧。

HTTP/2 协议规范_第20张图片

类似地,仅包括响应头字段的响应作为HEADERS帧(再次,随后是零个或更多个CONTINUATION帧)被传送,其包含响应头字段的串行化块。

HTTP/2 协议规范_第21张图片

包括请求头字段和有效载荷数据的HTTP POST请求作为一个HEADERS帧传送,随后是包含请求头字段的零个或多个CONTINUATION帧,随后是一个或多个DATA帧,最后一个CONTINUATION(或HEADERS)帧具有 END_HEADERS标志集和END_STREAM标志被设置的最终DATA帧:

HTTP/2 协议规范_第22张图片

HTTP/2 协议规范_第23张图片

下面的例子包括一个100(Continue)状态码,它是为了响应在Expect头域中包含“100-continue”标记的请求而发送的,以及尾头部域:

HTTP/2 协议规范_第24张图片

8.1.4 HTTP/2中请求可靠机制

在HTTP/1.1中,当发生错误时,HTTP客户端无法重试非幂等请求,因为无法确定错误的性质。某些服务器处理可能在错误发生之前发生,如果请求重新尝试,可能会导致不良后果。

HTTP/2提供了两种机制来为客户端提供一个请求尚未处理的保证:

  • GOAWAY帧指示可能已经处理的最高流号码。因此,数量较多的流上的请求可以保证可以安全地重试。
  • REFUSED_STREAM错误代码可以包含在RST_STREAM帧中,以指示在发生任何处理之前流正在关闭。可以安全地重试在重置流上发送的任何请求。

尚未处理的请求未失败;客户端可以自动重试它们,即使那些非幂等方法。服务器不能指出一个流没有被处理,除非它能保证这个事实。如果流中的帧传递给任何流的应用层,那么REFUSED_STREAM绝不能用于该流,并且GOAWAY帧必须包含一个大于或等于给定流标识符的流标识符。除了这些机制之外,PING框架为客户提供了一种轻松测试连接的方式。由于某些中间件(例如网络地址转换器或负载平衡器)默默丢弃连接绑定,因此保持空闲状态的连接可能会中断。 PING框架允许客户安全地测试连接是否仍然活动而不发送请求。

8.2 服务器推送

HTTP/2允许服务器先前发送(或“推送”)响应(连同相应的“承诺”请求)到与之前客户端发起的请求相关联的客户端。

客户端可以请求禁用服务器推送,尽管这是针对每一跳独立协商的。 SETTINGS_ENABLE_PUSH设置为0以表示服务器推送被禁用。

8.2.1 推送请求

服务器推送在语义上等同于响应请求的服务器;然而,在这种情况下,该请求也由服务器作为PUSH_PROMISE帧发送。 PUSH_PROMISE帧包含一个头部块,其中包含一组完整的请求头字段,服务器将该请求头归为请求。

8.2.2 推送响应

一旦客户端收到一个PUSH_PROMISE帧并选择接受推送的响应,那么客户端应该不会发出任何对承诺的响应的请求,直到承诺的流关闭之后。

如果客户端因任何原因确定不希望接收来自服务器的推送响应,或者如果服务器花费很长时间才开始发送承诺响应,则客户端可以使用CANCEL或REFUSED_STREAM发送RST_STREAM帧代码并引用推送流的标识符。

客户端可以使用SETTINGS_MAX_CONCURRENT_STREAMS设置来限制服务器可以同时推送的响应数量。通过将SETTINGS_MAX_CONCURRENT_STREAMS值设置为零,可以阻止服务器创建必要的流,从而禁用服务器推送。

注意:客户端永远不会为服务器推送发送带有END_STREAM标志的帧。

8.3 CONNECT 方法

在HTTP/1.x中,使用伪方法CONNECT([RFC7231],第4.3.6节)将HTTP连接转换为到远程主机的隧道。 为了与“https”资源进行交互,CONNECT主要与HTTP代理一起使用以与源服务器建立TLS会话。

在HTTP/2中,出于类似目的,CONNECT方法用于通过单个HTTP/2流建立到远程主机的隧道。 HTTP报头字段映射的工作方式与第8.1.2.3节(“请求伪报头字段”)中定义的一样,但有一些不同之处。 特别:

  • :method”伪头字段设置为“CONNECT”。
  • 必须省略“:scheme”和“:path”伪报头字段。
  • :authority”伪头字段包含要连接的主机和端口(相当于CONNECT请求的请求目标的权威形式(参见[RFC7230],第5.3节))。

不符合这些限制的CONNECT请求格式错误(第8.1.2.6节)。

支持CONNECT的代理建立到“:authority”伪头字段中标识的服务器的TCP连接[TCP]。一旦这个连接成功建立,代理发送一个包含2xx系列状态码的HEADERS帧给客户端,如[RFC7231]第4.3.6节中定义的那样。在每个对等方发送初始HEADERS帧之后,所有后续的DATA帧都对应于TCP连接上发送的数据。由客户端发送的任何数据帧的有效载荷由代理发送给TCP服务器;代理将从TCP服务器接收到的数据汇编到数据帧中。除了DATA或流管理帧(RST_STREAM,WINDOW_UPDATE和PRIORITY)之外的帧类型不得在连接的流上发送,并且必须被视为流错误(第5.4.2节)(如果收到)。 TCP连接可以由任何一方关闭。 DATA帧上的END_STREAM标志被视为等同于TCP FIN位。在收到一个带有END_STREAM标志的帧后,客户端需要发送带有END_STREAM标志的DATA帧。接收到带有END_STREAM标志集的DATA帧的代理会发送带有在最后一个TCP段上设置的FIN位的附加数据。接收到设置了FIN位的TCP段的代理将发送带有END_STREAM标志集的DATA帧。请注意,最终的TCP段或数据帧可能为空。

TCP连接错误通过RST_STREAM发送。 代理将TCP连接中的任何错误(包括接收到设置了RST位的TCP段)视为类型为CONNECT_ERROR的流错误(第5.4.2节)。 相应地,如果代理服务器检测到流或HTTP/2连接错误,则必须发送一个RST位设置的TCP段。

9 附加HTTP要求/注意事项

本节概述了HTTP协议的特性,这些特性可以提高互操作性,减少已知安全漏洞的暴露程度,或减少实施变化的可能性。

9.1 连接管理

HTTP/2连接是持久的。当任一端点选择关闭传输层TCP连接时,终止端点首先应发送一个GOAWAY(6.8节)帧,以便两个端点可以可靠地确定以前发送的帧是否已处理并正常完成或终止任何必需的剩余任务。

9.1.1 连接复用

可以直接或通过使用CONNECT方法创建的隧道(第8.3节)对源服务器进行的连接可以重用于具有多个不同URI授权组件的请求。只要源服务器具有权威性,连接就可以重用(第10.1节)。对于没有TLS的TCP连接,这取决于已解析为相同IP地址的主机。

不希望客户端重用连接的服务器可以通过发送421(Misdirected Request)状态码来响应请求(请参阅第9.1.2节),从而表明它对请求没有权威性。配置为通过HTTP/2使用代理的客户端通过单个连接将请求发送到该代理。也就是说,通过代理发送的所有请求都会重用到代理的连接。

9.1.2 421状态码

421(误导请求)状态码指示该请求是针对无法产生响应的服务器的。 这可以由服务器发送,该服务器未配置为针对包含在请求URI中的方案和权限的组合产生响应。 接收到来自服务器的421(误导请求)响应的客户端可以通过不同的连接重试请求 - 请求方法是否是幂等性的。 如果重新使用连接(第9.1.1节)或选择了替代服务[ALT-SVC],则可以这样做。 这个状态码不能由代理生成。 421响应默认是可缓存的,即除非方法定义或显式高速缓存控制另有指示(请参见[RFC7234]的第4.2.2节)。

9.2 TLS功能

HTTP/2的实现必须对TLS上的HTTP/2使用TLS版本1.2 [TLS12]或更高版本。

TLS实现必须支持TLS的服务器名称指示(SNI)[TLS-EXT]扩展。 在协商TLS时,HTTP/2客户端必须指明目标域名。

端点可以立即终止一个不符合这些TLS要求的HTTP/2连接,并带有INADEQUATE_SECURITY类型的连接错误。

在TLS 1.2上部署HTTP/2必须禁用压缩。

在TLS 1.2上部署HTTP / 2必须禁用重新协商。端点必须将TLS重新协商视为类型为PROTOCOL_ERROR的连接错误。

服务器可能会使用HTTP_1_1_REQUIRED类型的错误(第5.4节)来请求客户端使用支持重新协商的协议。实现必须支持至少2048位的临时密钥交换的尺寸为使用短暂的有限域的密码套件的Diffie-Hellman的(DHE)[TLS12]和224bit短暂的椭圆曲线的Diffie-Hellman(ECDHE)[RFC4492]。客户端必须接受最大4096位的DHE大小。端点可能会将小于下限的密钥大小的协商视为INADEQUATE_SECURITY类型的连接错误。

在TLS 1.2上部署HTTP/2不应使用密码套件黑名单(附录A)中列出的任何密码套件。如果协商出黑名单中的一个密码套件,则端点可以选择生成类型为INADEQUATE_SECURITY的连接错误。

为了避免导致TLS握手失败的问题,使用TLS 1.2的HTTP / 2的部署必须支持带有P-256椭圆曲线[FIPS186]的TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [TLS-ECDHE]。

Appendix A. TLS1.2 加密套件黑名单

详细请参考RFC7540。

你可能感兴趣的:(http-2)