Directrices de HTTP

En este documento se describe cómo funcionan las APIs de Google con diferentes versiones e implementaciones de HTTP. Si utilizas una de nuestras bibliotecas de cliente generadas o creadas manualmente (el método que recomendamos para la mayoría de los casos prácticos), no tienes que preocuparte por esto, ya que el código proporcionado se encarga de los problemas de bajo nivel de la comunicación con el servidor.

Sin embargo, si eres un desarrollador con experiencia y necesitas escribir tu propio código personalizado para acceder directamente a la interfaz REST de una API mediante una biblioteca de cliente HTTP de terceros de tu elección, debes conocer al menos parte de la semántica que se documenta aquí (en función de la API que elijas), así como lo que proporciona tu biblioteca HTTP.

Trabajar con protocolos de cable (HTTP/*)

En esta sección se describen los protocolos de transferencia admitidos (normalmente, una versión de HTTP) que pueden usar las APIs de Cloud para comunicarse entre clientes y servidores, así como la forma en que recomendamos usarlos. En la siguiente sección, veremos los detalles de cómo se estructuran las solicitudes y las respuestas.

Semántica HTTP

Cuando desarrolles código de cliente de la API, sigue la semántica del protocolo HTTP estándar. Los proxies del lado del servidor o las pilas de APIs solo pueden admitir un subconjunto de funciones HTTP estándar y también pueden admitir sus versiones compatibles con versiones anteriores.

La pila del servidor controla la semántica del protocolo HTTP que deben gestionar las implementaciones del lado del servidor de las APIs. Solo debes usar esta semántica si estas funciones se documentan explícitamente como parte de la especificación de la API, como la compatibilidad con el almacenamiento en caché.

Versiones de HTTP

Los clientes pueden usar cualquier protocolo HTTP/*, según lo permita la plataforma del cliente o su red del lado del cliente, o según se negocie con el proxy del lado del servidor. Los protocolos admitidos son HTTP/1.0, HTTP/1.1, SPDY/*, HTTP/2 y QUIC.

Es posible que algunas funciones de la API solo sean compatibles con versiones más recientes de los protocolos HTTP, como el envío desde el servidor y las prioridades. Algunas solo se especifican por completo con HTTP/2, como el streaming bidireccional. Ten en cuenta las limitaciones de las diferentes versiones de HTTP si necesitas alguna de estas funciones como parte de la especificación de la API.

Por lo general, recomendamos HTTP/2 para mejorar el rendimiento y la resistencia a los fallos de red.

Canales

Los canales hacen referencia a las conexiones de red de la capa 4 (sockets TCP o UDP). Las aplicaciones cliente no deben presuponer cómo se usan los canales en el tiempo de ejecución para servir solicitudes HTTP. En casi todos los casos, los canales se terminan mediante proxies en nombre del proceso del servidor.

En el caso de los clientes HTTP/1.1, siempre se deben reutilizar las conexiones TCP (Connection: Keep-Alive). Es probable que la biblioteca de clientes HTTP también gestione un grupo de conexiones para mejorar el rendimiento. No envíes solicitudes en paralelo a través de la misma conexión TCP. Consulta más información sobre HTTP y TCP.

Todos los navegadores modernos usan SPDY/*, HTTP/2 o QUIC, que multiplexan las solicitudes a través de un solo canal. El límite de conexiones tradicional (de 2 a 10) nunca debería ser un problema, excepto cuando la implementación del servidor limite el número de solicitudes HTTP simultáneas de un solo cliente (por ejemplo, 100 flujos HTTP/2 en un solo origen).

HTTPS

Los clientes pueden acceder a una API a través de HTTPS o HTTP, según lo admitido por la especificación de la API. La negociación y las versiones de TLS son transparentes para las aplicaciones cliente. De forma predeterminada, las APIs de Google solo aceptan tráfico HTTPS.

Formatos de solicitud y respuesta

URLs de solicitud

La asignación JSON-REST admite datos de solicitud codificados en URL, y el cuerpo de la solicitud y la respuesta HTTP usan application/json como Content-Type.

El cuerpo HTTP usa una matriz JSON para admitir métodos RPC transmitidos, y la matriz JSON puede contener cualquier número de mensajes JSON o un mensaje JSON de estado de error.

URLs de solicitud largas

La URL tiene una limitación de longitud práctica, que suele ser de 16 KB de forma predeterminada, aunque puede variar en función del servidor. Si tu API usa solicitudes GET con URLs que superan esta longitud, es posible que las solicitudes no lleguen al servidor de la API de destino y que Google Front End (GFE) las rechace con el mensaje de error Your client has issued a malformed or illegal request..

Para evitar esta limitación, el código de cliente debe usar una solicitud POST con el tipo de contenido application/x-www-form-urlencoded y el encabezado HTTP X-HTTP-Method-Override: GET. Este método también funciona con las solicitudes DELETE.

Métodos HTTP (verbos)

Si las URLs de solicitud siguen el modelo REST, sus métodos HTTP se especifican como parte de la especificación de la API. En concreto, todos los métodos de la API deben cumplir los requisitos del protocolo HTTP en función del verbo HTTP específico al que se asigne el método de la API. Para obtener más información, consulta la especificación del protocolo de transferencia de hipertexto y la RFC del método PATCH.

Los métodos seguros, como GET y HEAD de HTTP, no deben representar ninguna acción que no sea la recuperación. En concreto, HTTP GET debe considerarse seguro y no debe tener ningún efecto secundario visible para el cliente.

La idempotencia en HTTP significa que los efectos secundarios de varias solicitudes idénticas son los mismos que los de una sola solicitud. GET, PUT y DELETE son los métodos HTTP idempotentes relevantes para la guía de estilo. Ten en cuenta que la idempotencia solo se expresa en términos de efectos secundarios del lado del servidor y no especifica nada sobre la respuesta. En concreto, DELETE para los recursos que no existen debería devolver 404 (Not Found).

HTTP POST y PATCH no son seguros ni idempotentes. (PATCH se introdujo en RFC 5789)

Verbo HTTP Seguro Idempotente
GET
PUT  
DELETE  
POST  
PATCH  

Formatos de carga útil

  • La solicitud y la respuesta deben compartir el mismo Content-Type, excepto cuando la solicitud sea GET o POST con un cuerpo application/x-www-form-urlencoded.

  • JSON se admite con el tipo MIME application/json. La asignación de proto3 a JSON se especifica formalmente en Asignación de JSON.

  • Los parámetros de formulario (POST) se pueden usar en lugar de los parámetros de consulta de URL (GET) siguiendo la misma regla de asignación de estilo REST para asignar campos de solicitud a parámetros de consulta. El Content-Type admitido es application/x-www-form-urlencoded.

Streaming

Semidúplex frente a dúplex completo

HTTP es un protocolo de solicitud-respuesta que permite que el cuerpo de la solicitud o de la respuesta se envíe a través de diferentes transportes orientados a flujos, como TCP (HTTP/1.x) o sus variantes multiplexadas (SPDY, HTTP/2 y QUIC).

Como desarrollador de clientes, tu aplicación puede generar el cuerpo de la solicitud en modo de streaming, es decir, streaming del cliente. Del mismo modo, la aplicación también puede consumir el cuerpo de la respuesta en modo de streaming, es decir, streaming del servidor.

Sin embargo, la especificación HTTP no indica si un servidor puede transmitir el cuerpo de la respuesta (excepto en el caso de las respuestas de error) cuando el cuerpo de la solicitud aún está pendiente. Esta semántica se conoce como streaming bidireccional. Aunque muchos softwares de cliente, servidor y proxy HTTP permiten el streaming full-duplex, incluso en HTTP/1.1, para evitar problemas de interoperabilidad, las APIs de Cloud basadas en HTTP solo admiten el streaming half-duplex.

De forma predeterminada, los métodos de streaming bidireccional de las APIs de Cloud asumen la semántica full-duplex. Es decir, no es seguro usar HTTP para invocar este método. Si un método de streaming es solo semidúplex (como lo aplica el servidor), el documento de la API debe especificar claramente el comportamiento semidúplex.

En el caso de los clientes de navegador, la semántica HTTP estándar se limita aún más con las APIs de red del navegador. Actualmente, los navegadores solo admiten la transmisión por servidor (que generalmente respeta el marco a nivel de transporte) a través de XHR o Fetch. La API Fetch usa streams de WHATWG.

Debido a las restricciones del navegador, las APIs de Cloud que requieren compatibilidad con el navegador deben evitar el streaming del cliente y el streaming bidireccional completo, o bien proporcionar una API independiente específicamente para los clientes del navegador.

En general, el streaming del cliente a través de Internet es menos útil que el streaming del servidor. Esto se debe a que el uso de la transmisión por streaming del cliente suele dar lugar a un servicio con estado, lo que afecta negativamente al equilibrio de carga y hace que el sistema sea más vulnerable a fallos o ataques. Por otro lado, el streaming del servidor puede ser útil, ya que puede reducir significativamente la latencia en redes con retrasos de RTT largos.

Codificación de mensajes

Los mensajes JSON que se envían por streaming se codifican como una matriz de mensajes JSON. El cuerpo de la solicitud o de la respuesta seguirá siendo un tipo MIME JSON válido.

Ejemplo de codificación de una secuencia de cliente:

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

Ejemplo de codificación de flujo de servidor:

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

Codificación a nivel de cable: la definición de StreamBody solo es significativa en su asignación de IDs de etiquetas a los campos "messages" y "status". Se codificará con varint con 1-2 bytes para los mensajes normales, por lo que la sobrecarga total de codificación será de 2-3 bytes por mensaje.

Se necesita un campo de relleno opcional para admitir flujos codificados en base64:

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

Los mensajes de error deben añadirse como el último elemento de la matriz JSON o protobuf, con el mismo formato que los mensajes normales.

Gestión de estados

El comportamiento de cierre parcial está bien definido en cualquier versión de HTTP para que un cliente o un servidor indiquen al otro extremo que el cuerpo se ha completado.

En concreto, el código de cliente puede completar la solicitud mientras sigue esperando la respuesta. Del mismo modo, un cliente puede ver una respuesta completada cuando el cuerpo de la solicitud aún se está escribiendo en el servidor. El estándar HTTP espera que el cliente cancele o complete la solicitud cuando una respuesta se completa de forma inesperada, normalmente con un estado de error. Es decir, en condiciones normales, el servidor no debería completar una respuesta cuando el cliente aún esté enviando la solicitud.

Cancelación

La asistencia para la cancelación permite a un cliente anular una solicitud cuando esta o la respuesta aún están pendientes.

No hay asistencia fiable para la cancelación de clientes HTTP/1.*, ya que un cliente puede cerrar una conexión TCP una vez completada la solicitud sin anular la transacción de solicitud/respuesta. En HTTP/1.1, un FIN de TCP no se debe interpretar como una cancelación, aunque la conexión esté marcada como keep-alive (Connection: Keep-Alive).

Sin embargo, después de que el cliente cierre la conexión TCP, si el servidor intenta escribir datos en el cliente, se generará un RST, que puede activar una cancelación.

Ten en cuenta que la cancelación también es un problema para las APIs que no son de streaming. Esto ocurre sobre todo cuando la respuesta implica un sondeo largo y, por lo tanto, la conexión puede permanecer inactiva durante un periodo prolongado.

Se admite la cancelación explícita con SPDY, HTTP/2 y QUIC, sobre todo con el mensaje go-away.

Keep-alive

La compatibilidad con Keep-Alive permite que un cliente o un servidor detecten un peer con errores, incluso en caso de pérdida de paquetes o fallos de red.

HTTP/1.1 no admite la función Keep-Alive, ya que Keep-Alive de TCP no es un enfoque viable.

QUIC o HTTP/2 ofrecen mensajes de control especiales para implementar la compatibilidad con keep-alive por parte de las aplicaciones, incluidos los navegadores.

Sin embargo, para que las conexiones keep-alive y la detección de errores sean fiables, es probable que se necesite una biblioteca de cliente con la asistencia del lado del servidor necesaria. A menudo, se producen errores al hacer streaming de larga duración a través de Internet si se usa HTTP básico como protocolo de comunicación.

Control de flujo

Para admitir el control de flujo, el cliente debe propagar los eventos de control de flujo a nivel de transporte a la aplicación cliente. El mecanismo real depende del estilo de la API de cliente HTTP que use tu aplicación cliente. Por ejemplo, necesitas lecturas y escrituras de bloqueo, o lecturas y escrituras sin bloqueo con compatibilidad explícita con el control de flujo para que las aplicaciones gestionen y respeten los eventos de control de flujo, con el fin de evitar que se sobrecarguen el cliente o el servidor.

HTTP/1.1 se basa en el control de flujo TCP.

SPDY y HTTP/2 tienen su propio control de flujo a nivel de flujo, que está sujeto al control de flujo de TCP a nivel de conexión, ya que las solicitudes se multiplexan a través de una sola conexión TCP.

QUIC se ejecuta en UDP y, por lo tanto, gestiona el control de flujo por completo.