Skip to main content

8. 在HTTP/2中表达HTTP语义 (Expressing HTTP Semantics in HTTP/2)

HTTP/2是HTTP消息抽象的一种实例化([HTTP]的第6节)。

8.1. HTTP消息帧 (HTTP Message Framing)

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

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

  1. 一个HEADERS帧(后跟零个或多个CONTINUATION帧),包含头部节(参见[HTTP]的第6.3节
  2. 零个或多个DATA帧,包含消息内容(参见[HTTP]的第6.4节
  3. 可选地,一个HEADERS帧(后跟零个或多个CONTINUATION帧),包含尾部节(如果存在)(参见[HTTP]的第6.5节

仅对于响应,服务器可以在包含最终响应的HEADERS帧之前发送任意数量的中间响应。中间响应由一个HEADERS帧(可能后跟零个或多个CONTINUATION帧)组成,包含中间(1xx) HTTP响应的控制数据和头部节(参见[HTTP]的第15节)。携带信息状态码且设置了END_STREAM标志的HEADERS帧是格式错误的(第8.1.1节)。

序列中的最后一帧带有END_STREAM标志,注意设置了END_STREAM标志的HEADERS帧后可以跟随携带字段块剩余片段的CONTINUATION帧。

来自任何流的其他帧不得出现在HEADERS帧和可能跟随的任何CONTINUATION帧之间。

HTTP/2使用DATA帧来承载消息内容。[HTTP/1.1]的第7.1节中定义的分块传输编码不能在HTTP/2中使用;参见第8.2.2节。

尾部字段承载在也终止流的字段块中。也就是说,尾部字段包含一个以HEADERS帧开始的序列,后跟零个或多个CONTINUATION帧,其中HEADERS帧带有END_STREAM标志。尾部不得包含伪头部字段(第8.3节)。接收到尾部中包含伪头部字段的端点必须将请求或响应视为格式错误(第8.1.1节)。

端点在接收到打开请求的HEADERS帧之后,或在接收到最终(非信息性)状态码之后,接收到未设置END_STREAM标志的HEADERS帧时,必须将相应的请求或响应视为格式错误(第8.1.1节)。

HTTP请求/响应交换完全消耗单个流。请求从将流置于"打开"状态的HEADERS帧开始。请求以设置了END_STREAM标志的帧结束,这会导致流对于客户端变为"半关闭(本地)"状态,对于服务器变为"半关闭(远程)"状态。响应流以零个或多个HEADERS帧中的中间响应开始,后跟包含最终状态码的HEADERS帧。

在服务器发送(或客户端接收)设置了END_STREAM标志的帧(包括完成字段块所需的任何CONTINUATION帧)之后,HTTP响应完成。如果响应不依赖于尚未发送和接收的请求的任何部分,服务器可以在客户端发送整个请求之前发送完整响应。当这种情况成立时,服务器可以在发送完整响应(即设置了END_STREAM标志的帧)后,通过发送带有NO_ERROR错误码的RST_STREAM来请求客户端中止请求传输而不产生错误。客户端不得因接收到此类RST_STREAM而丢弃响应,尽管客户端出于其他原因始终可以自行决定丢弃响应。

8.1.1. 格式错误的消息 (Malformed Messages)

格式错误的请求或响应是指在其他方面是有效的HTTP/2帧序列,但由于存在无关帧、禁止的字段或伪头部字段、缺少强制性伪头部字段、包含大写字段名称或无效的字段名称和/或值(在某些情况下;参见第8.2节)而无效的消息。

包含消息内容的请求或响应可以包含content-length头部字段。如果content-length头部字段的值不等于构成内容的DATA帧有效载荷长度之和,则请求或响应也是格式错误的,除非消息被定义为没有内容。例如,204或304响应不包含内容,对HEAD请求的响应也是如此。如[HTTP]的第6.4.1节所述,被定义为没有内容的响应可以有非零的content-length头部字段,即使DATA帧中不包含内容。

处理HTTP请求或响应的中间节点(即,不作为隧道的任何中间节点)不得转发格式错误的请求或响应。检测到的格式错误的请求或响应必须被视为PROTOCOL_ERROR类型的流错误(第5.4.2节)。

对于格式错误的请求,服务器可以在关闭或重置流之前发送HTTP响应。客户端不得接受格式错误的响应。

渐进处理消息的端点可能在将请求或响应识别为格式错误之前已经执行了一些处理。例如,可能在未收到完整请求的情况下生成信息性或404状态码。类似地,中间节点可能在检测到错误之前转发不完整的消息。当响应不依赖于请求的其余部分正确时,服务器可以在接收到整个请求之前生成最终响应。

这些要求旨在防止针对HTTP的几种常见攻击类型;它们特意严格,因为宽容可能会使实现暴露于这些漏洞。

8.2. HTTP字段 (HTTP Fields)

HTTP字段([HTTP]的第5节)由HTTP/2在HEADERS、CONTINUATION和PUSH_PROMISE帧中传递,使用HPACK [COMPRESSION]压缩。

在构造HTTP/2消息时,字段名称必须转换为小写。

8.2.1. 字段有效性 (Field Validity)

HTTP中字段名称和值的定义禁止某些HPACK可能能够传递的字符。HTTP/2实现应该根据[HTTP]的第5.1节和第5.5节中的定义验证字段名称和值,并将包含禁止字符的消息视为格式错误(第8.1.1节)。

未能验证字段可能被用于请求走私攻击。特别是,当使用HTTP/1.1 [HTTP/1.1]转发消息时,未经验证的字段可能启用攻击,其中回车符(CR)、换行符(LF)和冒号等字符用作分隔符。实现必须对字段名称和值执行以下最小验证:

  • 字段名称不得包含0x00-0x20、0x41-0x5a或0x7f-0xff范围内的字符(所有范围包括边界)。这特别排除了所有不可见的ASCII字符、ASCII空格(0x20)和大写字符('A'到'Z',ASCII 0x41到0x5a)
  • 除了伪头部字段(第8.3节)(其名称以单个冒号开头)之外,字段名称不得包含冒号(ASCII冒号,0x3a)
  • 字段值不得在任何位置包含零值(ASCII NUL,0x00)、换行符(ASCII LF,0x0a)或回车符(ASCII CR,0x0d)
  • 字段值不得以ASCII空白字符(ASCII空格或制表符,0x20或0x09)开始或结束

包含违反这些条件中任何一个的字段的请求或响应必须被视为格式错误(第8.1.1节)。特别是,在转发消息时不处理字段的中间节点不得转发包含任何上述禁止值的字段。

当请求消息违反这些要求之一时,实现应该生成400(Bad Request)状态码(参见[HTTP]的第15.5.1节),除非定义了更合适的状态码或无法发送状态码(例如,因为错误发生在尾部字段中)。

8.2.2. 连接特定头部字段 (Connection-Specific Header Fields)

HTTP/2不使用Connection头部字段([HTTP]的第7.6.1节)来指示连接特定的头部字段;在此协议中,连接特定的元数据通过其他方式传递。端点不得生成包含连接特定头部字段的HTTP/2消息。这包括Connection头部字段以及[HTTP]的第7.6.1节中列为具有连接特定语义的字段(即Proxy-ConnectionKeep-AliveTransfer-EncodingUpgrade)。包含连接特定头部字段的任何消息必须被视为格式错误(第8.1.1节)。

唯一的例外是TE头部字段,它可以出现在HTTP/2请求中;当存在时,它不得包含除"trailers"之外的任何值。

将HTTP/1.x消息转换为HTTP/2的中间节点必须按照[HTTP]的第7.6.1节中讨论的那样删除连接特定的头部字段,否则它们的消息将被其他HTTP/2端点视为格式错误(第8.1.1节)。

Cookie头部字段[COOKIE]使用分号(";")来分隔cookie对(或"碎片")。此头部字段包含多个值,但不使用逗号(",")作为分隔符,从而防止cookie对在多个字段行上发送(参见[HTTP]的第5.2节)。这可能会显著降低压缩效率,因为对各个cookie对的更新会使存储在HPACK表中的任何字段行失效。

为了获得更好的压缩效率,Cookie头部字段可以拆分为单独的头部字段,每个字段具有一个或多个cookie对。如果解压缩后有多个Cookie头部字段,则必须在传递到非HTTP/2上下文(例如HTTP/1.1连接或通用HTTP服务器应用程序)之前,使用0x3b、0x20的双八位组分隔符(ASCII字符串"; ")将它们连接成单个八位组字符串。

因此,以下两个Cookie头部字段列表在语义上是等效的:

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

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

8.3. HTTP控制数据 (HTTP Control Data)

HTTP/2使用以':'字符(ASCII 0x3a)开头的特殊伪头部字段来传递消息控制数据(参见[HTTP]的第6.2节)。

伪头部字段不是HTTP头部字段。端点不得生成本文档中定义的伪头部字段之外的伪头部字段。注意,扩展可以协商使用额外的伪头部字段;参见第5.5节。

伪头部字段仅在定义它们的上下文中有效。为请求定义的伪头部字段不得出现在响应中;为响应定义的伪头部字段不得出现在请求中。伪头部字段不得出现在尾部节中。端点必须将包含未定义或无效伪头部字段的请求或响应视为格式错误(第8.1.1节)。

所有伪头部字段必须出现在字段块中所有常规字段行之前。包含出现在常规字段行之后的字段块中的伪头部字段的任何请求或响应必须被视为格式错误(第8.1.1节)。

相同的伪头部字段名称不得在字段块中出现多次。包含重复伪头部字段名称的HTTP请求或响应的字段块必须被视为格式错误(第8.1.1节)。

8.3.1. 请求伪头部字段 (Request Pseudo-Header Fields)

为HTTP/2请求定义了以下伪头部字段:

":method"伪头部字段包含HTTP方法([HTTP]的第9节)。

":scheme"伪头部字段包含请求目标的方案部分。当直接生成请求时,方案取自目标URI([RFC3986]的第3.1节),或者取自翻译请求的方案(例如,参见[HTTP/1.1]的第3.3节)。对于CONNECT请求,方案被省略(第8.5节)。

":scheme"不限于"http"和"https"方案的URI。代理或网关可以翻译非HTTP方案的请求,从而允许使用HTTP与非HTTP服务交互。

":authority"伪头部字段传达目标URI的权限部分([RFC3986]的第3.2节)([HTTP]的第7.1节)。如果存在":authority",HTTP/2请求的接收者不得使用Host头部字段来确定目标URI。

直接生成HTTP/2请求的客户端必须使用":authority"伪头部字段来传达权限信息,除非没有要传达的权限信息(在这种情况下,它不得生成":authority")。

客户端不得生成Host头部字段与":authority"伪头部字段不同的请求。如果请求包含标识与":authority"伪头部字段中的实体不同的实体的Host头部字段,服务器应该将该请求视为格式错误。字段的值需要规范化以进行比较(参见[RFC3986]的第6.2节)。源服务器可以应用任何规范化方法,而其他服务器必须对两个字段执行基于方案的规范化(参见[RFC3986]的第6.2.3节)。

通过HTTP/2转发请求的中间节点必须使用原始请求的控制数据中的权限信息构造":authority"伪头部字段,除非原始请求的目标URI不包含权限信息(在这种情况下,它不得生成":authority")。注意,Host头部字段不是此信息的唯一来源;参见[HTTP]的第7.2节

需要生成Host头部字段(这可能是构造HTTP/1.1请求所必需的)的中间节点必须使用":authority"伪头部字段的值作为Host字段的值,除非中间节点也更改了请求目标。这将替换任何现有的Host字段,以避免HTTP路由中的潜在漏洞。

通过HTTP/2转发请求的中间节点可以保留任何Host头部字段。

注意,CONNECT或星号形式OPTIONS请求的请求目标从不包含权限信息;参见[HTTP]的第7.1节和第7.2节。

对于"http"或"https"方案的URI,":authority"不得包含已弃用的userinfo子组件。

":path"伪头部字段包含目标URI的路径和查询部分(absolute-path产生式以及可选的'?'字符后跟query产生式;参见[HTTP]的第4.1节)。星号形式的请求(用于OPTIONS)为":path"伪头部字段包含值'*'。

对于"http"或"https" URI,此伪头部字段不得为空;不包含路径组件的"http"或"https" URI必须包含值'/'。此规则的例外情况是:

  • 不包含路径组件的"http"或"https" URI的OPTIONS请求;这些请求必须包含值为'*'的":path"伪头部字段(参见[HTTP]的第7.1节
  • CONNECT请求(第8.5节),其中省略了":path"伪头部字段

所有HTTP/2请求必须恰好包含":method"、":scheme"和":path"伪头部字段的一个有效值,除非它们是CONNECT请求(第8.5节)。省略强制性伪头部字段的HTTP请求是格式错误的(第8.1.1节)。

各个HTTP/2请求不携带协议版本的显式指示符。所有HTTP/2请求隐式具有"2.0"的协议版本(参见[HTTP]的第6.2节)。

8.3.2. 响应伪头部字段 (Response Pseudo-Header Fields)

对于HTTP/2响应,定义了单个":status"伪头部字段,该字段携带HTTP状态码字段(参见[HTTP]的第15节)。此伪头部字段必须包含在所有响应中,包括中间响应;否则,响应是格式错误的(第8.1.1节)。

HTTP/2响应隐式具有"2.0"的协议版本。

8.4. 服务器推送 (Server Push)

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

服务器推送旨在允许服务器通过预测将跟随它接收到的请求的请求来改善客户端感知的性能,从而为它们消除往返时间。例如,对HTML的请求通常后跟对该页面引用的样式表和脚本的请求。当推送这些请求时,客户端不需要等待在HTML中接收到对它们的引用并发出单独的请求。

在实践中,服务器推送很难有效使用,因为它要求服务器正确预测客户端将发出的额外请求,同时考虑缓存、内容协商和用户行为等因素。预测错误可能导致性能下降,因为线路上额外数据所代表的机会成本。特别是,推送任何大量数据都可能导致与更重要的响应发生争用问题。

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

承诺的请求必须是安全的(参见[HTTP]的第9.2.1节)且可缓存的(参见[HTTP]的第9.2.3节)。承诺的请求不能包含任何内容或尾部节。接收到不可缓存、不知道是安全的或指示存在请求内容的承诺请求的客户端必须使用PROTOCOL_ERROR类型的流错误(第5.4.2节)重置承诺的流。注意,如果客户端不识别新定义的方法为安全的,这可能导致承诺的流被重置。

可缓存的推送响应(参见[CACHING]的第3节)可以由客户端存储(如果它实现了HTTP缓存)。在承诺的流标识符标识的流仍然打开时,推送响应被认为在源服务器上成功验证(例如,如果存在"no-cache"缓存响应指令;参见[CACHING]的第5.2.2.4节)。

不可缓存的推送响应不得由任何HTTP缓存存储。它们可以单独提供给应用程序。

服务器必须在":authority"伪头部字段中包含服务器具有权威性的值(参见第10.1节)。客户端必须将服务器不具有权威性的PUSH_PROMISE视为PROTOCOL_ERROR类型的流错误(第5.4.2节)。

中间节点可以从服务器接收推送并选择不将其转发给客户端。换句话说,如何使用推送的信息取决于该中间节点。同样,中间节点可能选择在没有服务器采取任何行动的情况下向客户端进行额外推送。

客户端不能推送。因此,服务器必须将接收到PUSH_PROMISE帧视为PROTOCOL_ERROR类型的连接错误(第5.4.1节)。服务器不能将SETTINGS_ENABLE_PUSH设置设置为0以外的值(参见第6.5.2节)。

8.4.1. 推送请求 (Push Requests)

服务器推送在语义上等同于服务器响应请求;然而,在这种情况下,该请求也由服务器作为PUSH_PROMISE帧发送。

PUSH_PROMISE帧包含一个字段块,该字段块包含控制数据和服务器归属于请求的一组完整的请求头部字段。不可能推送包含消息内容的请求的响应。

承诺的请求始终与来自客户端的显式请求相关联。服务器发送的PUSH_PROMISE帧在该显式请求的流上发送。PUSH_PROMISE帧还包括一个承诺的流标识符,从服务器可用的流标识符中选择(参见第5.1.1节)。

PUSH_PROMISE和任何后续CONTINUATION帧中的头部字段必须是有效且完整的请求头部字段集(第8.3.1节)。服务器必须在":method"伪头部字段中包含安全且可缓存的方法。如果客户端接收到不包含完整且有效的头部字段集或":method"伪头部字段标识的方法不安全的PUSH_PROMISE,它必须在承诺的流上以PROTOCOL_ERROR类型的流错误(第5.4.2节)响应。

服务器应该在发送任何引用承诺响应的帧之前发送PUSH_PROMISE(第6.6节)帧。这避免了客户端在接收到任何PUSH_PROMISE帧之前发出请求的竞争。

例如,如果服务器接收到包含嵌入到多个图像文件的链接的文档的请求,并且服务器选择将这些额外图像推送到客户端,则在包含图像链接的DATA帧之前发送PUSH_PROMISE帧可确保客户端能够在发现嵌入链接之前看到将推送资源。类似地,如果服务器推送字段块引用的资源(例如,在Link头部字段中),则在发送头部之前发送PUSH_PROMISE可确保客户端不会请求这些资源。

PUSH_PROMISE帧不得由客户端发送。

PUSH_PROMISE帧可以由服务器在任何客户端发起的流上发送,但相对于服务器,该流必须处于"打开"或"半关闭(远程)"状态。PUSH_PROMISE帧穿插在组成响应的帧之间,尽管它们不能穿插在组成单个字段块的HEADERS和CONTINUATION帧之间。

发送PUSH_PROMISE帧会创建一个新流,并将流置于服务器的"保留(本地)"状态和客户端的"保留(远程)"状态。

8.4.2. 推送响应 (Push Responses)

在发送PUSH_PROMISE帧之后,服务器可以开始在使用承诺的流标识符的服务器发起的流上作为响应(第8.3.2节)传递推送的响应。服务器使用此流传输HTTP响应,使用第8.1节中定义的相同帧序列。在发送初始HEADERS帧之后,此流对于客户端变为"半关闭"状态(第5.1节)。

一旦客户端接收到PUSH_PROMISE帧并选择接受推送的响应,客户端在承诺的流关闭之前不应该为承诺的响应发出任何请求。

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

客户端可以使用SETTINGS_MAX_CONCURRENT_STREAMS设置来限制服务器可以并发推送的响应数量。将SETTINGS_MAX_CONCURRENT_STREAMS值设为零可防止服务器打开推送响应所需的流。但是,这不会阻止服务器使用PUSH_PROMISE帧保留流,因为保留的流不计入并发流限制。不希望接收推送资源的客户端需要重置任何不需要的保留流或将SETTINGS_ENABLE_PUSH设置为0。

接收推送响应的客户端必须验证服务器具有权威性(参见第10.1节)或提供推送响应的代理已为相应请求配置。例如,仅为example.com DNS-ID提供证书的服务器(参见[RFC6125])不允许推送<https://www.example.org/doc>的响应。

PUSH_PROMISE流的响应以HEADERS帧开始,该帧立即将流置于服务器的"半关闭(远程)"状态和客户端的"半关闭(本地)"状态,并以设置了END_STREAM标志的帧结束,该帧将流置于"关闭"状态。

8.5. CONNECT方法 (The CONNECT Method)

CONNECT方法([HTTP]的第9.3.6节)用于将HTTP连接转换为到远程主机的隧道。CONNECT主要与HTTP代理一起使用,以建立与源服务器的TLS会话,用于与"https"资源交互。

在HTTP/2中,CONNECT方法在单个HTTP/2流上建立到远程主机的隧道,而不是将整个连接转换为隧道。CONNECT头部节按照第8.3.1节("请求伪头部字段")中的定义构造,但有一些差异。具体来说:

  • ":method"伪头部字段设置为CONNECT
  • ":scheme"和":path"伪头部字段必须省略
  • ":authority"伪头部字段包含要连接的主机和端口(等同于CONNECT请求的request-target的authority-form;参见[HTTP/1.1]的第3.2.3节

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

支持CONNECT的代理建立到":authority"伪头部字段中标识的主机和端口的TCP连接[TCP]。一旦此连接成功建立,代理向客户端发送包含2xx系列状态码的HEADERS帧,如[HTTP]的第9.3.6节中所定义。

在每个对等方发送的初始HEADERS帧之后,所有后续DATA帧对应于在TCP连接上发送的数据。客户端发送的任何DATA帧的帧有效载荷由代理传输到TCP服务器;从TCP服务器接收的数据由代理组装成DATA帧。除了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段或DATA帧可以为空。

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

8.6. Upgrade头部字段 (The Upgrade Header Field)

HTTP/2不支持101(Switching Protocols)信息状态码([HTTP]的第15.2.2节)。

101(Switching Protocols)的语义不适用于多路复用协议。类似的功能可能通过使用扩展CONNECT [RFC8441]启用,其他协议能够使用HTTP/2用于协商其使用的相同机制(参见第3节)。

8.7. 请求可靠性 (Request Reliability)

一般来说,当发生错误时,HTTP客户端无法重试非幂等请求,因为没有办法确定错误的性质(参见[HTTP]的第9.2.2节)。可能在错误之前发生了一些服务器处理,如果重新尝试请求,可能会导致不良后果。

HTTP/2提供了两种机制来向客户端保证请求尚未被处理:

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

尚未被处理的请求尚未失败;客户端可以自动重试它们,即使是具有非幂等方法的请求。

服务器不得指示流尚未被处理,除非它可以保证该事实。如果流上的帧被传递到任何流的应用层,则不得对该流使用REFUSED_STREAM,并且GOAWAY帧必须包含大于或等于给定流标识符的流标识符。

除了这些机制之外,PING帧提供了一种让客户端轻松测试连接的方法。保持空闲的连接可能会损坏,因为某些中间箱(例如,网络地址转换器或负载均衡器)会默默丢弃连接绑定。PING帧允许客户端安全地测试连接是否仍然活动,而无需发送请求。

8.8. 示例 (Examples)

本节展示了HTTP/1.1请求和响应,以及等效HTTP/2请求和响应的示例。

8.8.1. 简单请求 (Simple Request)

HTTP GET请求包括控制数据和不带消息内容的请求头部,因此作为单个HEADERS帧传输,后跟零个或多个包含序列化请求头部字段块的CONTINUATION帧。以下HEADERS帧同时设置了END_HEADERS和END_STREAM标志;不发送CONTINUATION帧。

  GET /resource HTTP/1.1           HEADERS
Host: example.org ==> + END_STREAM
Accept: image/jpeg + END_HEADERS
:method = GET
:scheme = https
:authority = example.org
:path = /resource
host = example.org
accept = image/jpeg

8.8.2. 简单响应 (Simple Response)

类似地,仅包含控制数据和响应头部的响应作为HEADERS帧(再次,后跟零个或多个CONTINUATION帧)传输,包含序列化的响应头部字段块。

  HTTP/1.1 304 Not Modified        HEADERS
ETag: "xyzzy" ==> + END_STREAM
Expires: Thu, 23 Jan ... + END_HEADERS
:status = 304
etag = "xyzzy"
expires = Thu, 23 Jan ...

8.8.3. 复杂请求 (Complex Request)

包含控制数据和带有消息内容的请求头部的HTTP POST请求作为一个HEADERS帧传输,后跟零个或多个包含请求头部的CONTINUATION帧,后跟一个或多个DATA帧,最后一个CONTINUATION(或HEADERS)帧设置了END_HEADERS标志,最后一个DATA帧设置了END_STREAM标志:

  POST /resource HTTP/1.1          HEADERS
Host: example.org ==> - END_STREAM
Content-Type: image/jpeg - END_HEADERS
Content-Length: 123 :method = POST
:authority = example.org
{binary data} :path = /resource
:scheme = https

CONTINUATION
+ END_HEADERS
content-type = image/jpeg
host = example.org
content-length = 123

DATA
+ END_STREAM
{binary data}

注意,对任何给定字段行有贡献的数据可能分散在字段块片段之间。此示例中字段行到帧的分配仅用于说明。

8.8.4. 带正文的响应 (Response with Body)

包含控制数据和带有消息内容的响应头部的响应作为HEADERS帧传输,后跟零个或多个CONTINUATION帧,后跟一个或多个DATA帧,序列中的最后一个DATA帧设置了END_STREAM标志:

  HTTP/1.1 200 OK                  HEADERS
Content-Type: image/jpeg ==> - END_STREAM
Content-Length: 123 + END_HEADERS
:status = 200
{binary data} content-type = image/jpeg
content-length = 123

DATA
+ END_STREAM
{binary data}

8.8.5. 信息响应 (Informational Responses)

使用除101之外的1xx状态码的信息响应作为HEADERS帧传输,后跟零个或多个CONTINUATION帧。

尾部节在请求或响应字段块和所有DATA帧都已发送之后作为字段块发送。启动包含尾部节的字段块的HEADERS帧设置了END_STREAM标志。

以下示例包括100(Continue)状态码(在响应包含Expect头部字段中的"100-continue"令牌的请求时发送)和尾部节:

  HTTP/1.1 100 Continue            HEADERS
Extension-Field: bar ==> - END_STREAM
+ END_HEADERS
:status = 100
extension-field = bar

HTTP/1.1 200 OK HEADERS
Content-Type: image/jpeg ==> - END_STREAM
Transfer-Encoding: chunked + END_HEADERS
Trailer: Foo :status = 200
content-type = image/jpeg
123 trailer = Foo
{binary data}
0 DATA
Foo: bar - END_STREAM
{binary data}

HEADERS
+ END_STREAM
+ END_HEADERS
foo = bar