Caching
🎯 Objetivo
Regla
12.1: Se debe aprovechar el mecanismo de caché HTTP estándar para mejorar el rendimiento, reducir la carga del servidor y disminuir la latencia para los clientes.
12.2: La implementación correcta de encabezados de caché es obligatoria para respuestas de GET y HEAD que sean cacheables.
📖 Concepto y Definición
Regla
12.3: El caching HTTP permite que las respuestas de la API sean almacenadas temporalmente (en el cliente, en proxies intermedios) y reutilizadas para solicitudes subsecuentes idénticas, evitando contactar al servidor de origen si la copia en caché aún es válida. 12.4: Los mecanismos clave obligatorios para controlar el caching son los encabezados HTTP:
Cache-Control(Respuesta): Debe ser el encabezado principal para definir la política de caché. Directivas comunes y obligatorias a usar según corresponda:public: La respuesta puede ser cacheada por cualquier caché (cliente, proxy).private: La respuesta es específica para un usuario y solo debe ser cacheada por el cliente final (navegador), no por proxies compartidos.no-cache: La caché debe revalidar con el servidor de origen antes de usar una copia almacenada (usandoETagoLast-Modified). No significa "no cachear", sino "revalidar siempre".no-store: La respuesta no debe ser almacenada en ninguna caché bajo ninguna circunstancia. Es la directiva más restrictiva.max-age=<segundos>: Especifica el tiempo máximo que la respuesta se considera fresca.s-maxage=<segundos>: Similar amax-age, pero aplica solo a cachés compartidas (proxies).must-revalidate: Indica que la caché debe revalidar una vez que la respuesta se vuelve obsoleta (max-ageexpira). No debe servir contenido obsoleto.
ETag(Respuesta): Debe usarse para caché basada en validación. Es un identificador opaco y único para una versión específica de un recurso. El servidor debe incluirlo en respuestasGET/HEAD.Last-Modified(Respuesta): Puede usarse como alternativa o complemento aETag, indicando la fecha de última modificación del recurso. Su granularidad es menor queETag.If-None-Match(Solicitud): El cliente debe enviar elETagrecibido previamente en este encabezado para revalidar su copia en caché. Si elETagen el servidor coincide, el servidor debe responder con304 Not Modified(sin cuerpo).If-Modified-Since(Solicitud): El cliente debe enviar la fechaLast-Modifiedrecibida previamente en este encabezado. Si el recurso no ha sido modificado desde esa fecha, el servidor debe responder con304 Not Modified(sin cuerpo).Vary(Respuesta): Debe usarse para indicar qué encabezados de la solicitud (además de la URI y el método) influyeron en la selección de la representación de la respuesta (ej.Accept,Accept-Language). Esto asegura que diferentes solicitudes (ej. pidiendo JSON vs XML) se cacheen por separado.
🤔 ¿Por qué es Importante? / Beneficios Clave (Contexto)
- Mejora del Rendimiento Percibido: Respuestas más rápidas para el cliente.
- Reducción de Carga del Servidor: Menos solicitudes llegan al origen.
- Ahorro de Ancho de Banda: Se transfiere menos data (especialmente con
304). - Escalabilidad: Contribuye a manejar más carga.
✅ Buenas Prácticas y Recomendaciones Clave
Regla
12.5: Las respuestas para solicitudes GET y HEAD deben incluir encabezados Cache-Control y ETag (o Last-Modified) para habilitar el caching y la validación.
12.6: La elección de las directivas Cache-Control (public, private, no-cache, max-age) debe basarse en la naturaleza del recurso:
- Recursos estáticos o públicos que cambian raramente: Usar
publicconmax-agelargo. - Recursos específicos de un usuario autenticado: Usar
privateconmax-ageadecuado ono-cache(requiriendo revalidación). - Recursos que cambian muy frecuentemente o deben estar siempre actualizados: Usar
no-cache(para permitir almacenamiento pero forzar revalidación) ono-store(si no debe almacenarse nunca). 12.7: Se debe preferir el uso deETagsobreLast-Modifiedpara validación, ya que ofrece mayor precisión. 12.8: La generación deETagdebe basarse en el contenido real de la respuesta. Un hash del cuerpo de la respuesta es un método común y recomendado. 12.9: El servidor debe procesar correctamente los encabezados condicionales de la solicitud (If-None-Match,If-Modified-Since) y devolver304 Not Modifiedcon cuerpo vacío si la condición se cumple. Esto es obligatorio para una implementación eficiente del caché. 12.10: El encabezadoVarydebe incluirse si la respuesta depende de otros encabezados además de la URI y el método. Como mínimo, debería incluirseVary: Acceptsi se soporta negociación de contenido.
Don'ts (Prohibido):
- 12.11: No se debe cachear respuestas de métodos no seguros/no idempotentes (
POST,PUT,DELETE,PATCH) por defecto, a menos que se indique explícitamente con encabezadosCache-Controly se entiendan las implicaciones. - 12.12: No se debe configurar caché agresiva (ej.
max-agelargo) para recursos que cambian frecuentemente o contienen datos sensibles que podrían quedar obsoletos. - 12.13: No se debe omitir el encabezado
Varysi la respuesta depende de encabezados de la solicitud (ej.Accept,Accept-Language), ya que podría llevar a servir contenido incorrecto desde la caché. - 12.14: No se debe implementar lógica de caché personalizada si los mecanismos estándar HTTP son suficientes.
💡 Ejemplos Prácticos (Ilustrativos)
Ejemplo 1: Respuesta Cacheable con ETag y Max-Age
// Respuesta a GET /products/prod_abc
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=3600 // Cacheable por 1 hora por cualquiera
ETag: "xyz789hash"
Vary: Accept
{
"productId": "prod_abc",
"name": "Widget",
"description": "A standard widget."
}
Ejemplo 2: Solicitud de Revalidación del Cliente
// Solicitud subsecuente para el mismo producto
GET /products/prod_abc HTTP/1.1
Host: api.example.com
Accept: application/json
If-None-Match: "xyz789hash" // Envía el ETag que tenía
Ejemplo 3: Respuesta del Servidor si el Recurso no Cambió
// Si el ETag en el servidor sigue siendo "xyz789hash"
HTTP/1.1 304 Not Modified
Cache-Control: public, max-age=3600
ETag: "xyz789hash"
Vary: Accept
// SIN CUERPO DE RESPUESTA
El cliente debe usar su copia cacheada.
Ejemplo 4: Respuesta para Datos Privados del Usuario
// Respuesta a GET /users/me/profile
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: private, no-cache // Solo caché privada, revalidar siempre
ETag: "user_profile_hash_123"
Vary: Accept
{
"userId": "user123",
"email": "private@example.com",
// ... más datos privados ...
}
🛠️ Herramientas y Consideraciones Adicionales (Contexto)
- CDNs (Content Delivery Networks): Pueden actuar como cachés compartidas muy eficaces, especialmente para APIs públicas.
- API Gateways: Muchos ofrecen funcionalidades de caché integradas.
- Invalidación de Caché: Es uno de los problemas difíciles. El uso de
ETagyno-cacheomax-agecortos ayuda, pero para invalidaciones activas se pueden requerir estrategias más complejas (no cubiertas por el estándar HTTP básico). - Consistencia: Los valores
ETagdeben ser consistentes entre múltiples instancias del servidor si se usa balanceo de carga.