Lineamientos HTTP

Es importante comprender cómo funcionan las APIs de Google con varias versiones e implementaciones de HTTP si escribes código personalizado que accede a la interfaz de REST de una API con un cliente HTTP de terceros. Para la mayoría de las cargas de trabajo, usa las bibliotecas cliente recomendadas de Google en su lugar, que controlan automáticamente la comunicación de servidor de bajo nivel que se analiza en este documento.

Trabaja con protocolos de conexión estándar (HTTP/*)

En esta sección, se describen los protocolos de conexión estándar compatibles (por lo general, una versión de HTTP) que las APIs de Google pueden usar para comunicarse entre clientes y servidores, y cómo te recomendamos que los uses.

Semántica de HTTP

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

La pila del servidor controla la semántica del protocolo HTTP que deben controlar las implementaciones del servidor de las APIs. Solo confía en esa semántica si estas funciones están documentadas de forma explícita 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 cliente o su red del cliente, o según lo negociado con el proxy del servidor. Los protocolos compatibles incluyen HTTP/1.1, HTTP/2 y HTTP/3 (QUIC). Se recomienda no usar la compatibilidad heredada con HTTP/1.0.

Es posible que algunas funciones de la API solo sean compatibles con versiones más recientes de los protocolos HTTP. Algunas solo se especifican por completo con HTTP/2 y HTTP/3, como la transmisión multiplexada de dúplex completo. 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. Ten en cuenta que las funciones más antiguas, como el push desde servidor HTTP/2, están obsoletas y no son compatibles con los clientes web modernos.

En general, recomendamos HTTP/3 o HTTP/2 para obtener un mejor rendimiento, reducir el bloqueo de línea y aumentar la resiliencia a las fallas de la red.

Canales

Los canales hacen referencia a las conexiones de red de capa 4, que suelen ser sockets TCP para HTTP/1.1 y HTTP/2, y sockets UDP para HTTP/3 (QUIC). Las aplicaciones cliente no deben hacer suposiciones sobre cómo se administran los canales de extremo a extremo, ya que los proxies de Google Front End (GFE) casi siempre finalizan las conexiones en nombre del proceso del servidor.

Clientes HTTP/1.1: Si usas HTTP/1.1, siempre vuelve a usar las conexiones TCP (Connection: Keep-Alive). Por lo general, las bibliotecas cliente de HTTP administran un grupo de conexiones para facilitar la reutilización. Evita el canalización de HTTP en conexiones HTTP/1.1. No es compatible y puede generar problemas. Para obtener más información, consulta HTTP y TCP.

Clientes HTTP/2 y HTTP/3: Los clientes y navegadores modernos usan principalmente HTTP/2 o HTTP/3. Ambos protocolos admiten la multiplexación, lo que permite que varias solicitudes y respuestas estén en tránsito de forma simultánea a través de una sola conexión.

  • HTTP/2: Usa una sola conexión TCP por origen.
  • HTTP/3: Usa una sola conexión QUIC a través de UDP por origen. QUIC integra el encriptado TLS, el control de congestión y la administración de conexiones, lo que suele proporcionar beneficios como una configuración de conexión más rápida (0-RTT o 1-RTT) y la inmunidad al bloqueo de línea TCP en las transmisiones.

Con HTTP/2 y HTTP/3, los límites del navegador en la cantidad de conexiones TCP paralelas a un solo host (por ejemplo, de 2 a 10) ya no son una preocupación principal de rendimiento. Sin embargo, ten en cuenta que los servidores (o los proxies como GFE) aún pueden aplicar límites en la cantidad máxima de transmisiones simultáneas dentro de una sola conexión HTTP/2 o HTTP/3. Esto evita la sobrecarga y garantiza un uso justo de los recursos (por ejemplo, limitando las solicitudes o transmisiones simultáneas por conexión a 100).

HTTPS

Los clientes pueden acceder a una API con HTTPS o HTTP, según lo admita la especificación de la API. La negociación de TLS y las versiones de TLS son transparentes para las aplicaciones cliente. De manera predeterminada, las API de Google solo aceptan tráfico HTTPS.

Formatos de solicitudes y respuestas

En esta sección, se describe la estructura de las interacciones de la API, incluido el uso de datos codificados en URL, métodos HTTP específicos para acciones de RESTful y formatos de carga útil basados en JSON.

URL de solicitud

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

El cuerpo HTTP usa un array JSON para admitir métodos RPC transmitidos, y el array JSON puede contener cualquier cantidad 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 establecerse en 16 KB de forma predeterminada, aunque puede variar según el 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 la limitación, el código del cliente debe usar una solicitud POST con un Content-Type de application/x-www-form-urlencoded junto con el encabezado HTTP X-HTTP-Method-Override: GET. Este enfoque también funciona para las solicitudes DELETE.

Métodos HTTP (verbos)

Si las solicitudes URL siguen el modelo REST, sus métodos HTTP se especifican como parte de la especificación de la API. En particular, cada método de API debe cumplir con los requisitos del protocolo HTTP según el verbo HTTP específico al que se asigna el método de 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 HTTP GET y HEAD, no deben representar una acción que no sea la recuperación. En particular, de GET de HTTP debe considerarse seguro y no tener efectos secundarios visibles para el cliente.

En HTTP, Idempotencia significa que los efectos secundarios de múltiples solicitudes idénticas son los mismos que para una sola solicitud. GET, PUT y DELETE son los métodos HTTP idempotentes relevantes a la guía de estilo. Ten en cuenta que la idempotencia solo se expresa en términos de efectos secundarios del servidor y no especifica nada sobre la respuesta. En particular, DELETE para recursos no existentes debe mostrar 404 (Not Found).

POST y PATCH de HTTP no son seguros ni idempotentes (PATCH se incluyó en la RFC 5789).

Verbo HTTP Seguro Idempotente
GET Sí Sí
PUT   Sí
DELETE   Sí
POST  
PATCH  

Formatos de carga útil

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

  • JSON es compatible con el tipo de MIME application/json. El mapeo de proto3 a JSON se especifica de manera formal en Mapeo 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 compatible es application/x-www-form-urlencoded.

Transmisión

En esta sección, se detalla cómo las APIs de Google controlan la transmisión del cliente y del servidor, y se abordan específicamente las restricciones de la comunicación de dúplex medio frente a dúplex completo y los requisitos de codificación para los mensajes JSON transmitidos.

Dúplex medio frente a dúplex completo

HTTP es un protocolo de solicitud y respuesta que permite que su cuerpo de solicitud o respuesta se entregue en diferentes transportes orientados a transmisiones, como TCP (HTTP/1.x) o sus variantes multiplexadas (SPDY, HTTP/2, QUIC).

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

Sin embargo, la especificación de HTTP no especifica si un servidor puede transmitir el cuerpo de la respuesta (excepto las respuestas de error) cuando el cuerpo de la solicitud aún está pendiente. Esta semántica se conoce como transmisión de dúplex completo. Aunque muchos programas de software de cliente/servidor/proxy HTTP permiten la transmisión de dúplex completo, incluso para HTTP/1.1, para evitar cualquier problema de interoperabilidad, las APIs de Cloud basadas en HTTP se restringen solo a la transmisión de dúplex medio.

De manera predeterminada, los métodos de transmisión con oferta en las API de Cloud suponen la semántica de dúplex completo. Es decir, no es seguro usar HTTP para invocar este método. Si un método de transmisión es solo de dúplex medio (según lo aplica el servidor), el documento de la API debe especificar con claridad el comportamiento del dúplex medio.

En el caso de los clientes de navegadores, las semánticas de HTTP estándar están restringidas por las API de la red del navegador. Los navegadores admiten la transmisión del servidor (que, por lo general, respeta el marco de nivel de transporte) con XHR o Fetch. La API de Fetch usa transmisiones de whatwg.

Debido a las restricciones del navegador, las API de Cloud que requieren compatibilidad con navegadores deben evitar la transmisión de clientes, además de la transmisión de dúplex completo, o proporcionar una API separada específica para los clientes del navegador.

En general, la transmisión del cliente a través de Internet es menos útil que la transmisión del servidor. Esto se debe a que el uso de la transmisión del cliente suele generar un servicio con estado, lo que afecta de forma negativa el balanceo de cargas y hace que el sistema sea más vulnerable a fallas o ataques. Por otro lado, la transmisión del servidor puede ser útil, ya que puede reducir significativamente la latencia en redes con demoras de RTT largas.

Codificación de mensajes

Cuando se transmiten mensajes JSON, se codifican como un arreglo de mensajes JSON. El cuerpo de solicitud o respuesta se mantendrá como un tipo MIME JSON válido.

A continuación, se muestra un ejemplo de codificación de transmisión del cliente:

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

A continuación, se muestra un ejemplo de codificación de transmisión del servidor:

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

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

Se necesita un campo de relleno opcional para admitir transmisiones codificadas 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 anexarse como el último elemento del arreglo JSON o protobuf en el mismo formato que los mensajes regulares.

Administración de estado

El comportamiento de cierre parcial se encuentra bien definido en cualquier versión HTTP para que los clientes o servidores avisen al otro extremo que el cuerpo está completo.

En particular, el código del cliente está libre para completar la solicitud mientras espera 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 HTTP estándar espera que el cliente anule o cancele por completo la solicitud cuando una respuesta se completa de forma inesperada, por lo general, con un estado de error. Es decir, en condiciones normales, el servidor no debe completar una respuesta cuando el cliente aún envía la solicitud.

Cancelación

La compatibilidad con la cancelación le permite al cliente anular una solicitud cuando esta o la respuesta están pendientes.

No hay compatibilidad confiable con la cancelación para clientes HTTP/1.*, ya que un cliente puede cerrar una conexión TCP después de que se complete la solicitud sin anular la transacción de solicitud o respuesta. Un TCP FIN, en HTTP/1.1, no debe interpretarse como una cancelación, incluso cuando la conexión se marca como una conexión keep-alive (Connection: Keep-Alive).

Sin embargo, luego de que el cliente cierra la conexión TCP, si el servidor intenta escribir datos al cliente, se generará un RST, que puede activar una cancelación.

También ten en cuenta que la cancelación es un problema para las API que no transmiten. Este es el caso, en especial, cuando la respuesta implica una larga espera y, por lo tanto, la conexión puede permanecer inactiva durante un período prolongado.

La cancelación explícita es compatible con SPDY, HTTP/2 y QUIC, principalmente con el mensaje GOAWAY.

Keep-alive

La compatibilidad con keep-alive permite que el cliente o el servidor detecten un intercambio de tráfico con errores, incluso en pérdidas del paquete y fallas de la red.

No hay compatibilidad con keep-alive en HTTP/1.1 ya que keep-alive de TCP no es un enfoque viable.

QUIC o HTTP/2 ofrecen mensajes de control especiales con el propósito de implementar la compatibilidad con keep-alive en las aplicaciones, incluidos los navegadores.

Sin embargo, es probable que la detección de fallas y una conexión keep-alive confiable necesiten una biblioteca cliente con la compatibilidad debida del lado del servidor: las transmisiones de larga duración en Internet por lo general son propensas a errores cuando dependen de HTTP básico como protocolo de comunicación.

Control de flujo

La compatibilidad con el control de flujo requiere que el cliente propague 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 usa tu aplicación cliente. Por ejemplo, necesitas bloqueos de escritura y lectura, o lecturas y escrituras sin bloqueo con compatibilidad explícita con el control de flujo para que las aplicaciones controlen y respeten los eventos de control de flujo, para evitar que el cliente o el servidor se sobrecarguen.

HTTP/1.1 depende del control de flujo TCP.

SPDY y HTTP/2 tienen su propio control de flujo a nivel de transmisión, que está sujeto al control de flujo 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, administra el control de flujo por completo por sí mismo.