Diretrizes HTTP

Neste documento, descrevemos como as APIs do Google funcionam com versões e implementações HTTP diferentes. Se você está usando uma de nossas bibliotecas de cliente criadas manualmente ou geradas (nossa abordagem recomendada para a maioria dos casos de uso), não precisa se preocupar com isso, já que o código fornecido lida com os problemas de baixo nível de comunicação com o servidor.

No entanto, se você é um desenvolvedor experiente e precisa escrever seu próprio código personalizado para acessar diretamente a interface REST de uma API usando uma biblioteca de cliente HTTP de terceiros de sua escolha, é necessário entender pelo menos parte da semântica documentada aqui (de acordo com a relevância para a API escolhida), além de compreender o que é fornecido por sua biblioteca HTTP.

Como trabalhar com protocolos de transferência (HTTP/*)

Nesta seção, descrevemos os protocolos de transferência compatíveis (normalmente uma versão do HTTP) que as APIs do Cloud podem usar para fazer a comunicação entre clientes e servidores, e como recomendamos que você os use. Analisaremos os detalhes de como as solicitações e as respostas estão estruturadas na seção abaixo.

Semântica do HTTP

Ao desenvolver o código de cliente da API, siga a semântica do protocolo HTTP padrão. Os proxies do lado do servidor ou as pilhas da API podem ser compatíveis somente com um subconjunto de recursos HTTP padrão e também podem aceitar as versões compatíveis anteriores.

A semântica do protocolo HTTP que precisa ser manipulada pelas implementações do lado do servidor das APIs é controlada pela pilha do servidor. Confie nessa semântica apenas se esses recursos forem explicitamente documentados como parte da especificação da API, como o suporte ao armazenamento em cache.

Versões do HTTP

Os clientes podem usar qualquer protocolo HTTP/*, conforme permitido pela plataforma de cliente ou pela respectiva rede do lado dele, ou conforme negociado com o proxy do lado do servidor. Os protocolos compatíveis incluem HTTP/1.0, HTTP/1.1, SPDY/*, HTTP/2 e QUIC.

Alguns recursos da API podem ser compatíveis apenas com versões mais recentes de protocolos HTTP, como push do servidor e prioridades. Alguns são totalmente especificados com HTTP/2, como o streaming full-duplex. Se você precisar de algum desses recursos como parte da especificação da API, não se esqueça das limitações das diferentes versões do HTTP.

Geralmente, recomendamos HTTP/2 para melhor desempenho, bem como resiliência a falhas de rede.

Canais

Os canais se referem às conexões de rede L4 (soquetes TCP ou UDP). Os aplicativos de cliente não podem fazer nenhuma suposição sobre como os canais são usados no tempo de execução para atender solicitações HTTP. Em quase todos os casos, os canais são encerrados por proxies em favor do processo do servidor.

Para clientes HTTP/1.1, sempre reutilize conexões TCP (Connection: Keep-Alive). A biblioteca de cliente do HTTP provavelmente gerenciará também um pool de conexão para melhor desempenho. Não canalize solicitações sobre a mesma conexão TCP. Consulte HTTP e TCP para mais informações.

Todos os navegadores modernos compreendem SPDY/*, HTTP/2 ou QUIC, que multiplexa solicitações em um único canal. O limite de conexão tradicional (2-10) nunca será uma preocupação, exceto quando a implementação do servidor reduz o número de solicitações HTTP simultâneas de um único cliente, por exemplo, 100 streams de HTTP/2 sobre uma única origem.

HTTPS

Os clientes podem acessar uma API via HTTPS ou HTTP, conforme compatibilidade com a especificação da API. A negociação TLS e as versões TLS são transparentes para aplicativos cliente. Por padrão, as APIs do Google aceitam apenas tráfego HTTPS.

Formatos de solicitação/resposta

Solicitar URLs

O mapeamento JSON-REST é compatível com dados de solicitação codificados de URL, e a solicitação HTTP e o corpo de resposta usam application/json como Content-Type.

O corpo HTTP usa uma matriz JSON para a compatibilidade com métodos RPC em streaming, e essa matriz pode conter qualquer número de mensagens JSON ou uma mensagem JSON de status de erro.

URLs de solicitação longa

O URL tem uma limitação prática de comprimento, normalmente entre dois mil a oito mil. Ela é aplicada por alguns navegadores e proxies. Se a sua API usa solicitações GET com URLs que excedem a limitação de comprimento, elas podem ser rejeitadas pelos navegadores. Para ignorar a limitação, o código do cliente precisa usar uma solicitação POST com Content-Type de application/x-www-form-urlencoded junto com o cabeçalho HTTP X-HTTP-Method-Override: GET. Essa abordagem também funciona para solicitações DELETE.

Métodos HTTP (verbos)

Se os URLs de solicitação seguirem o modelo REST, os métodos HTTP deles serão parte da especificação da API. Em particular, cada método da API precisa cumprir os requisitos do protocolo HTTP com base no Verbo HTTP específico ao qual o método da API mapeia. Para detalhes, consulte a especificação do protocolo de transferência de hipertexto e o documento RFC do método PATCH.

Métodos seguros, como GET e HEAD do HTTP, não podem ser usados para representar uma ação que não seja a recuperação. Especificamente, o GET do HTTP precisa ser considerado seguro e não pode ter nenhum efeito colateral visível para o cliente.

Idempotência em HTTP significa que os efeitos colaterais de várias solicitações idênticas são os mesmos de uma única solicitação. GET, PUT e DELETE são os métodos HTTP idempotentes relevantes para o guia de estilo. Observe que a idempotência é expressada apenas em termos de efeitos colaterais do servidor e não especifica nada sobre a resposta. Em particular, DELETE para recursos não existentes precisa retornar 404 (Not Found).

POST e PATCH HTTP não são seguros nem idempotentes (PATCH foi incluído no RFC 5789).

Verbo HTTP Seguro Idempotente
GET Sim Sim
PUT   Sim
DELETE   Sim
POST  
PATCH  

Formatos de payload

  • A solicitação e a resposta precisam compartilhar o mesmo tipo de conteúdo, exceto quando a solicitação é um GET ou um POST com um corpo "application/x-www-form-urlencoded.

  • JSON é compatível com o tipo MIME application/json. O mapeamento de proto3 para JSON é especificado formalmente em Mapeamento do JSON.

  • Parâmetros de formulário (POST) podem ser usados ​​no lugar de parâmetros de consulta do URL (GET), seguindo a mesma regra de mapeamento de estilo REST para campos de solicitação a parâmetros de consulta. O Content-Type compatível é application/x-www-form-urlencoded.

Streaming

Half-duplex em comparação com full-duplex

O HTTP é um protocolo de solicitação-resposta que permite que o corpo de solicitação ou de resposta correspondente seja entregue em diferentes transportes orientados por stream, como TCP (HTTP/1.x) ou as variantes multiplexadas (SPDY, HTTP/2, QUIC).

Como desenvolvedor de clientes, seu aplicativo pode produzir o corpo da solicitação em um modo de streaming, ou seja, streaming de cliente. Da mesma forma, o aplicativo também pode consumir o corpo de resposta em um modo de streaming, ou seja, streaming de servidor.

No entanto, a especificação HTTP não define se um servidor pode fazer streaming do corpo da resposta (exceto para respostas de erro) quando o corpo da solicitação ainda está pendente. Essa semântica é conhecida como streaming full-duplex. Muitos softwares de cliente/servidor/proxy HTTP permitem o streaming full-duplex, mas, mesmo para HTTP/1.1, a fim de evitar qualquer problema de interoperabilidade, as APIs do Cloud baseadas em HTTP são restritas apenas a streaming half-duplex.

Por padrão, os métodos de streaming de lances nas APIs do Cloud pressupõem a semântica full-duplex. Ou seja, não é seguro usar HTTP para invocar esse método. Se um método de streaming for somente half-duplex (conforme exigido pelo servidor), o documento da API precisará especificar claramente o comportamento half-duplex.

Para clientes de navegador, a semântica HTTP padrão é restringida pelas APIs de rede do navegador. No momento, os navegadores são compatíveis apenas com streaming de servidor (que geralmente respeita o enquadramento no nível de transporte) via XHR ou Fetch. A API de busca faz o uso de fluxos whatwg.

Devido às restrições do navegador, as Cloud APIs que exigem suporte a navegadores precisam evitar streaming de clientes, bem como streaming full-duplex, ou fornecer uma API separada especificamente para clientes de navegador.

De modo geral, o streaming de clientes pela Internet é menos útil do que o streaming de servidor. Isso ocorre porque o uso de streaming de clientes geralmente leva a um serviço com monitoramento de estado, o que afeta negativamente o balanceamento de carga e torna o sistema mais vulnerável a falhas ou ataques. O streaming de servidor, por outro lado, pode ser útil, já que pode reduzir significativamente a latência em relação aos trabalhos novos com longos atrasos de RTT.

Codificação de mensagens

As mensagens JSON são codificadas como uma matriz no momento do streaming. O corpo de solicitação ou resposta permanecerá como um tipo JSON MIME válido.

Exemplo de codificação de streaming de cliente:

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

Exemplo de codificação de streaming de servidor:

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

Codificação no nível de transferência: a definição do StreamBody só é significativa na alocação de códigos de tags para o campo "mensagens", e "status" será codificado em varint com 1-2 bytes para mensagens normais, portanto a sobrecarga de codificação total é de 2-3 bytes por mensagem.

Um campo de preenchimento opcional é necessário para a compatibilidade com streams codificados por base64:

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

As mensagens de erro precisam ser anexadas como o último elemento da matriz protobuf ou JSON, no mesmo formato que as mensagens normais.

Gerenciamento do estado

O comportamento semifechado é bem definido em qualquer versão do HTTP para um cliente ou servidor a fim de sinalizar para a outra extremidade que o corpo está completo.

Em particular, o código de cliente estará livre para completar a solicitação quando ainda estiver aguardando a resposta. Da mesma forma, um cliente poderá ver uma resposta completa quando o corpo da solicitação ainda estiver sendo gravado no servidor. O padrão HTTP espera que o cliente cancele ou complete a solicitação quando uma resposta for concluída de maneira inesperada, normalmente com um status de erro. Isso significa dizer que, em condições normais, o servidor não completará uma resposta quando o cliente ainda estiver enviando a solicitação.

Cancelamento

A compatibilidade de cancelamento permite que um cliente anule uma solicitação quando ela ou a resposta ainda estiverem pendentes.

Não há compatibilidade de cancelamento confiável para clientes HTTP/1.*, uma vez que um cliente é livre para fechar uma conexão TCP depois que a solicitação tenha sido concluída sem cancelar a transação de solicitação/resposta. Um TCP FIN, em HTTP/1.1, não será interpretado como um cancelamento, mesmo quando a conexão estiver marcada como keep-alive (Connection: Keep-Alive).

No entanto, depois que o cliente tiver fechado a conexão TCP, se o servidor tentar gravar qualquer dado para o cliente, um RST será gerado, o que pode acionar um cancelamento.

Observe que o cancelamento também é um problema para APIs que não são de streaming. Esse é o caso quando a resposta envolve uma pesquisa longa e, consequentemente, a conexão pode ficar ociosa por um período prolongado.

O cancelamento explícito é compatível com SPDY, HTTP/2 e QUIC, principalmente com a mensagem de go-away.

Keep-alive

A compatibilidade com keep-alive permite que um cliente ou servidor detecte um par com falha mesmo no caso de perda de pacotes ou falhas de rede.

Não há compatibilidade com keep-alive HTTP/1.1, já que o keep-alive do TCP não é uma abordagem viável.

O QUIC ou o HTTP/2 oferecem mensagens de controle especiais com a finalidade de implementar a compatibilidade com keep-alive por aplicativos, incluindo navegadores.

No entanto, uma detecção confiável de falhas e keep-alive ​​provavelmente exigirá uma biblioteca de cliente com a compatibilidade necessária do lado do servidor: fazer streamings de longa duração pela Internet geralmente pode causar erros quando se confia em HTTP básico como protocolo de comunicação.

Controle de fluxo

A compatibilidade com o controle de fluxo exige que o cliente propague eventos desse tipo no nível de transporte para o aplicativo do cliente. O mecanismo real depende do estilo da API do cliente HTTP que seu aplicativo cliente usa. Por exemplo, você precisa de gravações e leituras incompatíveis ou compatíveis com versões anteriores que tenham compatibilidade com controle de fluxo explícito para aplicativos para lidar e respeitar os eventos de controle de fluxo, a fim de evitar que o cliente ou o servidor sejam sobrecarregados.

O HTTP/1.1 conta com o controle de fluxo TCP.

O SPDY e o HTTP/2 têm o próprio controle de fluxo no nível do stream, que está sujeito ao controle de fluxo TCP no nível da conexão, uma vez que as solicitações são multiplexadas em uma única conexão TCP.

O QUIC é executado no UDP. Portanto, ele gerencia integralmente o controle de fluxo por conta própria.