HTTP 准则

本文档介绍了 Google API 如何与不同的 HTTP 版本和实现结合使用。 如果您使用的是我们生成或专门编写的客户端库(我们建议的方法适用于大多数用例),您无需担心这一点,因为其中提供的代码可以处理与服务器通信的低层级问题。

但是,如果您是一位经验丰富的开发人员,并且需要编写自己的自定义代码以使用您选择的第三方 HTTP 客户端库直接访问 API 的 REST 接口,您至少应该了解此处记录的一些语义(与您选择的 API 相关)以及 HTTP 库提供的内容。

使用传输协议 (HTTP/*)

本部分介绍 Cloud API 可用于在客户端和服务器之间进行通信的支持的传输协议(通常是某个版本的 HTTP),以及我们为您建议的协议使用方式。我们将在下一部分详细介绍请求和响应的结构。

HTTP 语义

开发 API 客户端代码时,请遵循标准 HTTP 协议语义。服务器端代理或 API 堆栈可能仅支持标准 HTTP 功能的子集,并且还可能支持其向后兼容的版本。

需要由 API 的服务器端实现处理的 HTTP 协议语义由服务器堆栈控制。仅当这些功能明确记录为 API 规范(例如缓存支持)的一部分时,才能依赖此类语义。

HTTP 版本

客户端可以使用客户端平台或其客户端网络允许或者与服务器端代理协商的任何 HTTP/* 协议。支持的协议包括 HTTP/1.0、HTTP/1.1、SPDY/*、HTTP/2 和 QUIC。

某些 API 功能可能只有较新版本的 HTTP 协议(例如服务器推送和优先级)才支持;部分功能仅使用 HTTP/2(例如全双工流式传输)完全指定。如果您需要将这些功能中的任何功能作为 API 规范的一部分,请注意不同 HTTP 版本的限制。

通常,为了提高性能和网络故障的恢复能力,我们建议使用 HTTP/2。

渠道

信道是指 L4 网络连接(TCP 或 UDP 套接字)。客户端应用不应该针对在运行时中如何使用信道来提供 HTTP 请求作出任何假设。在几乎所有情况下,信道都是由代表服务器进程的代理来终止。

对于 HTTP/1.1 客户端,应始终重复使用 TCP 连接 (Connection: Keep-Alive);为了获得更好的性能,HTTP 客户端库也可能会管理连接池。请不要通过相同的 TCP 连接传递请求。如需了解详情,请参阅 HTTP 和 TCP

现代浏览器都使用 SPDY/*、HTTP/2 或 QUIC 进行通信,它们通过单个信道多路传输请求。除非服务器实现限制来自单个客户端的并发 HTTP 请求数(例如,针对单个源的 100 个 HTTP/2 信息流),否则传统的连接限制 (2-10) 永远不应该成为问题。

HTTPS

客户端可以通过 API 规范支持的 HTTPS 或 HTTP 访问 API。TLS 协商和 TLS 版本对客户端应用是透明的。默认情况下,Google API 仅接受 HTTPS 流量。

请求/响应格式

请求网址

JSON-REST 映射支持网址编码形式的请求数据,HTTP 请求和响应主体使用 application/json 作为 Content-Type

HTTP 主体使用 JSON 数组来支持流式 RPC 方法,JSON 数组可能包含任意数量的 JSON 消息或错误状态 JSON 消息。

长请求网址

网址具有实际长度限制,通常在 2k 到 8k 之间。此限制由一些浏览器和代理强制执行。如果您的 API 使用网址超过长度限制的 GET 请求,浏览器可能会拒绝此类请求。 要避开此限制,客户端代码应使用 Content-Type 为 application/x-www-form-urlencoded 的 POST 请求,且 HTTP 标头为 X-HTTP-Method-Override: GET。该方法也适用于 DELETE 请求。

HTTP 方法(动词)

如果请求网址符合 REST 模型,则将其 HTTP 方法指定为 API 规范的一部分。特别是,每种 API 方法都必须符合基于 API 方法映射到的特定 HTTP 动词的 HTTP 协议的要求。如需了解详情,请参阅超文本传输协议规范和 PATCH 方法 RFC。

安全方法(如 HTTP GETHEAD)不应表示检索以外的操作。具体来说,HTTP GET 应该安全,不应对客户端产生任何显而易见的副作用。

HTTP 中的幂等性意味着多个相同请求产生的副作用与单个请求相同。GETPUTDELETE 是与风格指南相关的幂等 HTTP 方法。请注意,幂等性仅通过服务器副作用的形式表示,并未指定有关响应的任何内容。特别是对于不存在的资源,DELETE 应该返回 404 (Not Found)

HTTP POSTPATCH 既不安全也不具有幂等性。(PATCHRFC 5789 中引入)

HTTP 动词 安全 幂等
GET
PUT  
DELETE  
POST  
PATCH  

负载格式

  • 请求和响应应共享相同的 Content-Type,除非请求是带有 application/x-www-form-urlencoded 主体的 GETPOST

  • JSON 在 application/json MIME 类型中受支持。从 proto3 到 JSON 的映射在 JSON 映射中正式指定。

  • 根据用于将请求字段映射到查询参数的相同 REST 样式映射规则,可以使用表单参数 (POST) 代替网址查询参数 (GET)。支持的 Content-Typeapplication/x-www-form-urlencoded

流式

半双工与全双工

HTTP 是一种请求响应协议,允许通过面向信息流的不同传输协议(如 TCP (HTTP/1.x))或其多路复用变体 (SPDY、HTTP/2、QUIC) 传递其请求或响应主体。

作为客户端开发人员,您的应用可以采用流式传输模式生成请求主体,即客户端流式传输。同样地,应用也可以采用流式传输模式使用响应主体,即服务器流式传输。

但是,HTTP 规范未指定在请求正文仍处于挂起状态时是否允许服务器流式传输回响应正文(错误响应除外)。这种语义称为全双工流式传输。尽管许多 HTTP 客户端/服务器/代理软件确实支持全双工流式传输,即使 HTTP/1.1 也支持,但为了避免出现任何互操作性问题,基于 HTTP 的 Cloud API 仅限于半双工流式传输。

默认情况下,Cloud API 中的出价 Bidi 流式传输方法会采用全双工语义。 也就是说,使用 HTTP 调用这样的方法是不安全的。如果流式传输方法仅为半双工(由服务器强制执行),则 API 文档应明确指定半双工行为。

对于浏览器客户端,标准 HTTP 语义进一步受浏览器网络 API 的限制。目前,浏览器仅通过 XHR 或 Fetch 支持服务器流式传输通常遵循传输级别的帧处理方式)。Fetch API 可以使用 whatwg 流

由于浏览器的限制,需要浏览器支持的 Cloud API 必须避免采用客户端流式传输以及全双工流式传输,或者为浏览器客户端提供单独的 API。

一般来说,通过互联网进行客户端流式传输不如服务器流式传输有用。这是因为使用客户端流式传输通常会导致有状态服务,这会对负载平衡造成负面影响,让系统更容易出现故障或受到攻击。另一方面,服务器流式传输可能很有用,因为它可以显着减少有长时间 RTT 延迟的网络上的延迟时间。

消息编码

JSON 消息在流式传输时将作为 JSON 消息数组进行编码。请求或响应正文将作为有效的 JSON MIME 类型保留。

客户端流式传输编码示例:

1 <length> <message-bytes> 1 <length> <message-bytes>  … EOF

服务器流式传输编码示例:

1 <length> <message-bytes>  … 2 <length> <status-bytes> EOF

线级编码:StreamBody 的定义仅在其为字段“messages”分配 tag-id 时才有意义,而“status”对于正常消息将采用 1-2 字节的 varint 编码,因此总的编码开销为每条消息 2-3 个字节

需要添加可选的填充字段,才能支持使用 base64 编码的流:

message StreamBody {
  repeated bytes message = 1;
  google.rpc.Status status = 2;
  repeated bytes padding = 15;   // max one-byte tag-id: xxx01111
}

错误消息应作为 JSON 或 protobuf 数组的最后一个元素附加,其格式与常规消息相同。

状态管理

适用于客户端或服务器的任何 HTTP 版本中都很好地定义了半关闭行为,旨在向另一端发送主体已完成的信号。

特别是,客户端代码在等待响应时可以自由完成请求。与之类似,当请求主体仍在写入服务器时,客户端可能会看到完成的响应。HTTP 标准要求客户端在以意外方式完成响应时(通常具有错误状态)中止或完成请求。 这就是说,在正常情况下,服务器不应在客户端仍在发送请求时完成响应。

取消

通过取消支持,客户端能够在请求或响应仍在等待处理时中止请求。

HTTP/1.* 客户端没有可靠的取消支持,因为客户端可在请求完成后随时关闭 TCP 连接,而不会中止请求/响应事务。采用 HTTP/1.1 的 TCP FIN 不应被解释为取消,即使连接被标记为保持 keep-alive (Connection: Keep-Alive) 也是如此。

但在客户端关闭 TCP 连接后,如果服务器尝试将任何数据写入客户端,则会生成 RST,这会触发取消。

另请注意,取消也是非流式传输 API 存在的问题。当响应涉及长轮询并且因此导致连接长时间保持空闲时,此问题尤其明显。

SPDY、HTTP/2 和 QUIC 支持显式取消,尤其是与 go-away 消息结合使用。

Keep-alive

通过 Keep-alive 支持,客户端或服务器能够检测到失败的对等体,即使在出现丢包或网络故障的情况下也是如此。

HTTP/1.1 不提供 keep-alive 支持,因为 TCP keep-alive 不是一种可行的方法。

QUIC 或 HTTP/2 提供特殊控制消息,旨在实现由应用(包括浏览器)提供的 keep-alive 支持。

但是,实现可靠的 keep-alive 和故障检测将可能需要有一个客户端库,加上必要的服务器端支持:如果依赖将基本 HTTP 作为通信协议,通过互联网进行长期流式传输通常容易出错。

流控制

流控制支持要求客户端将传输级流控制事件传播到客户端应用。实际的机制取决于客户端应用所使用的 HTTP 客户端 API 执行机制。例如,为了防止客户端或服务器过载,您需要使用显式流控制支持阻塞写入和读取或者非阻塞读取和写入,以便应用处理和遵循流控制事件。

HTTP/1.1 依赖于 TCP 流控制。

SPDY 和 HTTP/2 在流级别具有自己的流控制,由于请求通过单个 TCP 连接进行多路复用,因此它们在连接级别进一步受到 TCP 流控制的限制。

QUIC 在 UDP 上运行,因此可以完全自行管理流控制。