6. Stream Mapping and Usage (流映射和使用)
QUIC流提供可靠的按序字节传递,但不保证相对于其他流上的字节的传递顺序。在QUIC版本1中,包含HTTP帧的流数据由QUIC STREAM帧携带,但这种帧对HTTP帧层是不可见的。传输层缓冲并排序接收到的流数据,向应用程序公开可靠的字节流。虽然QUIC允许流内的无序传递,但HTTP/3不使用此功能。
QUIC流可以是单向的(仅从发起方到接收方传输数据)或双向的(在两个方向传输数据)。流可以由客户端或服务器发起。有关QUIC流的更多详细信息,请参见 [QUIC-TRANSPORT] 的第2节。
当HTTP字段和数据通过QUIC发送时,QUIC层处理大部分流管理。在使用QUIC时,HTTP不需要进行任何单独的多路复用:通过QUIC流发送的数据始终映射到特定的HTTP事务或整个HTTP/3连接上下文。
6.1. Bidirectional Streams (双向流)
所有客户端发起的双向流用于HTTP请求和响应。双向流确保响应可以轻松与请求关联。这些流称为请求流 (Request Streams)。
这意味着客户端的第一个请求发生在QUIC流0上,后续请求在流4、8等上。为了允许这些流打开,HTTP/3服务器应该 (SHOULD) 为允许的流数量和初始流流量控制窗口配置非零最小值。为了不必要地限制并行性,应该 (SHOULD) 同时允许至少100个请求流。
HTTP/3不使用服务器发起的双向流,尽管扩展可以定义这些流的用途。客户端必须 (MUST) 将接收到的服务器发起的双向流视为类型为H3_STREAM_CREATION_ERROR的连接错误 (Connection Error),除非已协商此类扩展。
6.2. Unidirectional Streams (单向流)
任一方向的单向流用于多种目的。目的由流类型 (Stream Type) 指示,该类型作为可变长度整数在流的开头发送。跟随此整数的数据的格式和结构由流类型确定。
Unidirectional Stream Header {
Stream Type (i),
}
图1:单向流头部
本文档中定义了两种流类型:控制流 (Control Streams)(第6.2.1节)和推送流 (Push Streams)(第6.2.2节)。[QPACK] 定义了两种额外的流类型。其他流类型可以通过HTTP/3的扩展定义;有关更多详细信息,请参见第9节。某些流类型是保留的(第6.2.3节)。
HTTP/3连接在其生命周期早期阶段的性能对单向流上数据的创建和交换敏感。过度限制这些流的数量或流量控制窗口的端点将增加远程对等方早期达到限制并被阻塞的机会。特别是,实现应该考虑远程对等方可能希望对其被允许使用的某些单向流行使保留流行为(第6.2.3节)。
每个端点需要为HTTP控制流创建至少一个单向流。QPACK需要两个额外的单向流,其他扩展可能需要更多流。因此,客户端和服务器发送的传输参数必须 (MUST) 允许对等方创建至少三个单向流。这些传输参数还应该 (SHOULD) 为每个单向流提供至少1,024字节的流量控制信用。
请注意,如果端点的对等方在创建关键单向流之前消耗了所有初始信用,则不需要授予额外的信用来创建更多单向流。端点应该 (SHOULD) 首先创建HTTP控制流以及强制扩展(如QPACK编码器和解码器流)所需的单向流,然后根据对等方的允许创建其他流。
如果流头部指示的流类型不受接收方支持,则流的其余部分无法被消费,因为其语义未知。未知流类型的接收方必须 (MUST) 中止读取流或丢弃传入数据而不进行进一步处理。如果中止读取,接收方应该 (SHOULD) 使用H3_STREAM_CREATION_ERROR错误码或保留错误码(第8.1节)。接收方禁止 (MUST NOT) 将未知流类型视为任何类型的连接错误。
由于某些流类型可能影响连接状态,接收方不应该 (SHOULD NOT) 在读取流类型之前丢弃来自传入单向流的数据。
实现可以 (MAY) 在知道对等方是否支持之前发送流类型。但是,可能修改现有协议组件(包括QPACK或其他扩展)的状态或语义的流类型,禁止 (MUST NOT) 在已知对等方支持之前发送。
除非另有规定,发送方可以关闭或重置单向流。接收方必须 (MUST) 容忍单向流在接收到单向流头部之前被关闭或重置。
6.2.1. Control Streams (控制流)
控制流由流类型0x00指示。此流上的数据由HTTP/3帧组成,如第7.2节所定义。
每一方必须 (MUST) 在连接开始时启动单个控制流,并将其SETTINGS帧作为此流上的第一个帧发送。如果控制流的第一个帧是任何其他帧类型,这必须 (MUST) 被视为类型为H3_MISSING_SETTINGS的连接错误。每个对等方只允许一个控制流;接收到声称是控制流的第二个流必须 (MUST) 被视为类型为H3_STREAM_CREATION_ERROR的连接错误。发送方禁止 (MUST NOT) 关闭控制流,接收方禁止 (MUST NOT) 请求发送方关闭控制流。如果任一控制流在任何时候关闭,这必须 (MUST) 被视为类型为H3_CLOSED_CRITICAL_STREAM的连接错误。连接错误在第8节中描述。
由于控制流的内容用于管理其他流的行为,端点应该 (SHOULD) 提供足够的流量控制信用以防止对等方的控制流被阻塞。
使用一对单向流而不是单个双向流。这允许任一对等方在能够发送数据时立即发送。根据QUIC连接上是否可用0-RTT,客户端或服务器可能首先能够发送流数据。
6.2.2. Push Streams (推送流)
服务器推送 (Server Push) 是HTTP/2中引入的可选功能,允许服务器在发出请求之前启动响应。有关更多详细信息,请参见第4.6节。
推送流由流类型0x01指示,后跟其履行的承诺的推送ID (Push ID),编码为可变长度整数。此流上的剩余数据由HTTP/3帧组成,如第7.2节所定义,并通过零个或多个临时HTTP响应后跟单个最终HTTP响应来履行承诺的服务器推送,如第4.1节所定义。服务器推送和推送ID在第4.6节中描述。
只有服务器可以推送;如果服务器接收到客户端发起的推送流,这必须 (MUST) 被视为类型为H3_STREAM_CREATION_ERROR的连接错误。
Push Stream Header {
Stream Type (i) = 0x01,
Push ID (i),
}
图2:推送流头部
客户端不应该 (SHOULD NOT) 在读取推送流头部之前中止读取推送流,因为这可能导致客户端和服务器在哪些推送ID已被消费方面产生分歧。
每个推送ID在推送流头部中只能 (MUST) 使用一次。如果客户端检测到推送流头部包含在另一个推送流头部中使用的推送ID,客户端必须 (MUST) 将其视为类型为H3_ID_ERROR的连接错误。
6.2.3. Reserved Stream Types (保留流类型)
格式为 0x1f * N + 0x21(N为非负整数值)的流类型被保留以行使忽略未知类型的要求。这些流没有语义,当需要应用层填充时可以发送它们。它们也可以 (MAY) 在当前未传输数据的连接上发送。端点禁止 (MUST NOT) 在收到时认为这些流具有任何含义。
有效载荷和流的长度由发送实现以任何方式选择。发送保留流类型时,实现可以 (MAY) 干净地终止流或重置它。重置流时,应该 (SHOULD) 使用H3_NO_ERROR错误码或保留错误码(第8.1节)。