Lineamientos HTTP

En este documento se describe cómo las API de Google funcionan con diferentes implementaciones y versiones de HTTP. Si usas una de nuestras bibliotecas cliente generadas o hechas de forma manual (nuestro enfoque recomendado para la mayoría de los casos prácticos), no debes preocuparte por esto, ya que el código provisto lidia con los problemas menores de comunicación con el servidor.

Sin embargo, si eres un desarrollador con experiencia y necesitas escribir tu propio código personalizado para acceder de forma directa a la interfaz REST de la API con una biblioteca cliente HTTP de terceros, al menos debes saber algo sobre la semántica documentada aquí (que sea relevante para tu API elegida) y lo que proporciona tu biblioteca HTTP.

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 API de Cloud pueden usar para la comunicación entre clientes y servidores, y cómo recomendamos usarlos. Profundizaremos en los detalles de cómo se estructuran las solicitudes y respuestas en la próxima sección.

Semántica de HTTP

Cuando desarrolles código de cliente de API, sigue la semántica de protocolo HTTP estándar. Puede que los proxies del lado del servidor o las pilas de API solo admitan un subconjunto de características HTTP estándar y quizás admitan las versiones compatibles con las anteriores.

La pila del servidor controla la semántica del protocolo HTTP que necesita la administración mediante implementaciones de API del lado del servidor. Solo depende de ella si estas características están documentadas de forma explícita como parte de las especificaciones de la API, como la asistencia de almacenamiento en caché.

Versiones de HTTP

Los clientes pueden usar cualquier protocolo HTTP/*, como se permite en la plataforma del cliente o en la red del lado del cliente, o como se negocia con el proxy del lado del servidor. Los protocolos admitidos incluyen HTTP/1.0, HTTP/1.1, SPDY/*, HTTP/2 y QUIC.

Algunas características de las API pueden ser compatibles solo con versiones más nuevas de los protocolos HTTP, como la extracción del servidor y las prioridades; algunas solo se especifican por completo con HTTP/2, como la transmisión dúplex completo. Ten en cuenta las limitaciones de las diferentes versiones de HTTP si necesitas cualquiera de estas características como parte de las especificaciones de la API.

Por lo general, recomendamos HTTP/2 para tener un mejor rendimiento y resiliencia a las fallas de red.

Canales

Los canales hacen referencia a las conexiones de red L4 (sockets TCP o UDP). Las aplicaciones cliente no deberían hacer suposiciones sobre cómo se usan los canales en el entorno de ejecución para entregar solicitudes HTTP. En casi todos los casos, los proxies finalizan canales en nombre de los procesos del servidor.

Para los clientes de HTTP/1.1, siempre vuelve a usar las conexiones TCP (Conexión: Keep-Alive); es probable que la biblioteca cliente de HTTP administre un grupo de conexiones para un mejor rendimiento. No canalices las solicitudes en la misma conexión TCP. Consulta HTTP y TCP para obtener más información.

Todos los navegadores modernos hablan SPDY/*, HTTP/2 o QUIC, lo que multiplexa solicitudes en un solo canal. El límite de conexión tradicional (entre 2 y 10) nunca debería ser una preocupación, excepto cuando la implementación del servidor regula la cantidad de solicitudes HTTP simultáneas de un cliente, por ejemplo, 100 transmisiones HTTP/2 en un solo origen.

HTTPS

Los clientes pueden acceder a una API a través de HTTPS o HTTP, como lo admite 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

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 arreglo JSON para admitir métodos RPC transmitidos. El arreglo JSON puede contener cualquier cantidad de mensajes JSON o un mensaje JSON de estado de error.

URL de solicitud larga

La URL tiene una limitación de longitud práctica, por lo general, entre 2,000 y 8,000. Algunos navegadores y proxies la ponen en práctica. Si tu API usa solicitudes GET con URL que exceden la limitación de longitud, puede que los navegadores rechacen esas solicitudes. Para omitir la limitación, el código de cliente debe usar una solicitud POST con el tipo de contenido 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 la API debe cumplir con los requisitos del protocolo HTTP basado en el verbo HTTP específico al que asigna el método de la API. Para obtener más detalles, 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 deberían representar una acción que no sea de recuperación. En particular, 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 debería 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
PUT  
DELETE  
POST  
PATCH  

Formatos de carga útil

  • La solicitud y la respuesta deben compartir el mismo tipo de contenido, excepto cuando la solicitud es GET o 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 forma (POST) pueden usarse en lugar de parámetros de consulta de URL (GET) con 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

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. Asimismo, la aplicació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 HTTP no indica si un servidor puede transmitir de vuelta el cuerpo de la respuesta (excepto por las respuestas de error) cuando el cuerpo de la solicitud todavía está pendiente. Esta semántica se conoce como transmisión de dúplex completo. Si bien muchos software de cliente, servidor o proxy HTTP admiten la transmisión de dúplex completo, incluso para HTTP/1.1, las API de Cloud basadas en HTTP se restringen a la transmisión de dúplex medio a fin de evitar problemas de interoperabilidad.

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. En la actualidad, los navegadores solo admiten la transmisión de servidores (que respetan el enmarcado de nivel de transporte) mediante XHR o Fetch. La API de recuperación usa transmisiones 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 términos generales, la transmisión del cliente en Internet es menos útil que la transmisión del servidor. Esto se debe a que usar la transmisión del cliente a veces lleva a un servicio con estado, que afecta de manera adversa 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 de forma significativa la latencia en las autopistas con demoras prolongadas de RTT.

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 la asignación de los ID de etiquetas para el campo “mensajes”. El campo “estado” se codificará con 1 o 2 bytes para mensajes normales, por lo que el total de sobrecarga de codificación es de entre 2 y 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. De manera similar, un cliente puede ver una respuesta completa cuando el cuerpo de la solicitud aún está en proceso de escritura 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 todavía está en proceso de enviar 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 una compatibilidad con la cancelación confiable para los clientes de HTTP/1.*, ya que el cliente tiene la libertad de cerrar una conexión TCP luego de que se complete la solicitud sin anular la transacción de solicitud o respuesta. TCP FIN, en HTTP/1.1, no debe interpretarse como una cancelación, incluso cuando la conexión está marcada como keep-alive (Conexión: 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. Esto sucede en particular cuando la respuesta incluye un sondeo largo y, por lo tanto, la conexión puede mantenerse inactiva por un período extendido.

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 para la implementación de la asistencia de keep-alive en 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 en la aplicación cliente. El mecanismo depende del estilo de la API del cliente de HTTP que tu aplicación cliente use. Por ejemplo, necesitas bloqueos de lectura y escritura, o bien operaciones de lectura y escritura de no bloqueo con compatibilidad explícita con el control de flujo para que las aplicaciones administren y respeten eventos de control de flujo a fin de prevenir 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 aún más al control de flujo TCP a nivel de conexión mientras las solicitudes se multiplexan en una sola conexión TCP.

QUIC se ejecuta en UDP y, por lo tanto, administra el control de flujo por cuenta propia.