¿Odias los anuncios? Ir Sin publicidad Hoy

Encabezados HTTP Cache-Control Qué significan realmente no-cache, no-store y max-age

Actualizado en

Una explicación práctica de las directivas Cache-Control — qué hacen los navegadores y los CDNs con no-cache, no-store, max-age, s-maxage y ETags. Incluyendo los errores que afectan a la mayoría de los desarrolladores en producción.

Encabezados HTTP Cache-Control: Qué significan realmente no-cache, no-store y max-age 1
ANUNCIO · ¿ELIMINAR?

Usted probablemente ha escrito Cache-Control: no-cache y asumido que el navegador omitiría completamente el caché. No lo hará. no-cache significa "revalidar antes de servir desde el caché". Si realmente desea que la respuesta nunca se almacene, eso es no-store. Esta confusión causa errores de datos obsoletos en producción que son difíciles de diagnosticar porque todo parece bien en la pestaña de Redes en la primera carga.

Vamos a revisar cada directiva claramente — qué hacen los navegadores con ella, qué hacen los CDNs con ella, y los errores que surgen al mezclarlas.

Referencia completa de las directivas Cache-Control

DirectivaComportamiento del navegadorComportamiento del CDN / proxyUso típico
max-age=NAlmacenar durante N segundosAlmacenar durante N segundos (a menos que s-maxage sobrescriba)Recursos estáticos, respuestas de API
s-maxage=NIgnoradoAlmacenar durante N segundosTTL del CDN separado del navegador
no-cacheAlmacenar pero revalidar cada solicitudAlmacenar pero revalidar cada solicitudContenido que cambia frecuentemente con ETags
no-storeNo almacenar en ningún lugarNo almacenar en ningún lugarRespuestas de autenticación, datos sensibles del usuario
must-revalidateSin entrega obsoleta — revalidar o fallarSin entrega obsoleta — revalidar o fallarRespuestas de API donde la obsolescencia significa que el contenido es incorrecto
proxy-revalidateIgnoradoSin entrega obsoleta en cachés compartidosDebe revalidar en CDNs específicos
privateEl navegador puede cachearloNo debe cachearsePáginas específicas del usuario
publicCualquier caché puede almacenarlaPuede cachearlaRecursos estáticos compartidos
immutableNunca revalidar dentro del max-ageVaría según el CDNRecursos hashados o versionados
stale-while-revalidate=NServir contenido obsoleto durante N segundos mientras se obtiene el frescoVaría según el CDNVelocidad sin obsolescencia dura

max-age y s-maxage: TTL del navegador vs CDN

max-age=N indica cuántos segundos la respuesta es fresca. Después de N segundos, la respuesta almacenada se vuelve obsoleta y debe revalidarse antes de su uso.

s-maxage=N es exclusiva para CDNs. Los navegadores la ignoran completamente. Si desea que un CDN almacene durante una hora pero el navegador solo durante 5 minutos:

Cache-Control: max-age=300, s-maxage=3600

El navegador almacena durante 5 minutos. CloudFront, Fastly, Nginx — ellos usarán 3600 segundos. Una trampa común: establecer max-age=0 creyendo que desactiva el caché. No lo hace. max-age=0 significa que la respuesta se vuelve inmediatamente obsoleta — el navegador aún la almacena y la revalida, probablemente recibiendo un 304. Si nunca desea que se almacene, use no-store.

no-cache: No lo que piensas

Cache-Control: no-cache no significa "no usar el caché". Significa "no servir desde el caché sin revalidar primero con el servidor".

La secuencia cuando el navegador tiene una respuesta almacenada con no-cache:

  1. una nueva solicitud llega para el recurso almacenado
  2. El navegador envía el ETag de la respuesta almacenada (a través de If-None-Match) o la marca de última modificación al servidor
  3. Si el contenido no ha cambiado → el servidor devuelve 304 Not Modified sin cuerpo
  4. Si el contenido ha cambiado → el servidor devuelve 200 OK con la nueva respuesta

La ventaja sobre no-store: aún obtienes ahorro de ancho de banda de respuestas 304. Si tu contenido cambia ocasionalmente pero debe ser fresco cuando cambia, no-cache combinado con un ETag es la combinación adecuada.

no-store: El verdadero "No almacene esto"

Cache-Control: no-store significa que la respuesta no debe almacenarse en ningún lugar — ni en el caché del navegador, ni en un CDN, ni en un proxy intermedio. Ninguna copia, punto final.

Usa esto para:

  • Respuestas de autenticación (tokens de inicio de sesión, datos de sesión)
  • Datos personales sensibles
  • Contenido de una sola vez (confirmaciones de pago, páginas de OTP)

Una sutileza: no-store no impide que una página aparezca en el caché de navegación hacia atrás (bfcache). Los navegadores mantienen una copia en memoria para el rendimiento de navegación que es independiente del caché HTTP. Si necesitas manejar problemas con el botón atrás después de cerrar sesión, conecta al evento pageshow y verifica event.persisted.

must-revalidate: Sin gracia obsoleta

Los especificaciones de caché HTTP permiten que los cachés sirvan respuestas obsoletas cuando el origen no está disponible — una característica de resiliencia que la mayoría de los desarrolladores no conocen. must-revalidate elimina esa flexibilidad: una vez que una respuesta almacenada se vuelve obsoleta, el caché debe revalidar o devolver un 504. No se sirve contenido obsoleto en ningún caso.

# Without must-revalidate: CDN may serve stale if origin is slow or down
Cache-Control: max-age=3600

# With must-revalidate: stale = error, not a fallback
Cache-Control: max-age=3600, must-revalidate

Usa esto para respuestas de API donde servir datos obsoletos rompe la funcionalidad — contadores de inventario, precios, estado de autenticación — en lugar de simplemente que se vea un poco mal.

private vs public: El error del CDN que revela datos del usuario

private significa que la respuesta está destinada a un usuario específico. Los navegadores pueden cachearla; los cachés compartidos (CDNs, proxies inversos) no deben hacerlo.

public permite que cualquier caché — incluyendo los compartidos — almacene la respuesta. Algunos cachés solo almacenan respuestas de solicitudes autenticadas si se marca explícitamente public.

El error real que causa esto: un desarrollador copia y pega Cache-Control: public, max-age=3600 de un recurso estático a una página que incluye datos específicos del usuario. El CDN almacena la respuesta. El usuario B hace la misma solicitud y obtiene la página de Usuario A desde el caché. Esto no es teórico — GitHub tuvo una variante de esto en 2018. Marca explícitamente las respuestas autenticadas o específicas del usuario private aunque creas que tu CDN "sabe" que no debe almacenarlas.

ETags y solicitudes condicionales

Los ETags son cómo el servidor dice "aquí está una huella de esta respuesta". El navegador almacena el ETag junto con la respuesta almacenada y lo envía de vuelta en la siguiente solicitud a través de If-None-Match. Si el contenido no ha cambiado, el servidor devuelve 304 Not Modified sin cuerpo — misma enfoque de frescura que no-cache, mucho menos ancho de banda.

El no-cache + Flujo de ETag:

→ GET /api/config HTTP/1.1

← HTTP/1.1 200 OK
   Cache-Control: no-cache
   ETag: "abc123"
   [full response body]

→ GET /api/config HTTP/1.1
   If-None-Match: "abc123"

← HTTP/1.1 304 Not Modified
   [no body — browser uses its cached copy]

Dos tipos de ETag:

  • ETags fuertes ("abc123") — idénticos byte a byte. Requeridos para el soporte de solicitudes de rango en CDNs.
  • ETags débiles (W/"abc123") — semanticamente equivalentes pero no necesariamente idénticos en bytes. Adecuados para la revalidación en el navegador, no para solicitudes de rango.

Nginx genera ETags automáticamente a partir de la hora de modificación del archivo y su tamaño. Express no los agrega por defecto — usa el middleware app.set('etag', 'strong') o el etag explicitamente.

Last-Modified y If-Modified-Since

Concepto similar a ETags pero más grueso — basado en timestamp en lugar de en hash de contenido. El servidor incluye Last-Modified; el navegador envía If-Modified-Since en las solicitudes subsiguientes.

El problema: si reemplazas y las horas de modificación del archivo se actualizan aunque el contenido no haya cambiado, los cachés se invalidan innecesariamente. Un ETag basado en hash de contenido no tendrá este problema. Usa ETags cuando sea posible y trata a Last-Modified como un respaldo para servidores que no soporten ETags.

Vary: El encabezado que multiplica silenciosamente tu caché

El Vary encabezado indica que la respuesta puede diferir según otros encabezados de solicitud. Cada combinación única de esos encabezados obtiene su propia entrada en el caché.

Vary: Accept-Encoding

Esto indica que los cachés deben almacenar respuestas separadas para compresión gzip, brotli y identidad. Correcto y común. El peligroso uno: Vary: Cookie. Cada usuario tiene un conjunto único de cookies, por lo que cada usuario obtiene su propia entrada en el caché — efectivamente desactiva el caché compartido. Muchos frameworks agregan Vary: Cookie silenciosamente. Si tu tasa de aciertos en el caché del CDN es inexplicably baja a pesar de valores generosos de max-age , revisa tus encabezados de respuesta por Vary: Cookie que estén apareciendo desde el middleware de sesión.

Vary: * significa "no cachear esto en realidad" — cada solicitud se trata como única. Es equivalente a no-store para CDNs.

Forzar actualizaciones con parámetros de consulta

Cuando necesitas forzar descargas frescas de recursos versionados, agregar un parámetro de consulta es el enfoque estándar — la cadena de consulta forma parte de la URL, por lo que se trata como un recurso nuevo tanto para navegadores como para CDNs:

/app.js?v=2.1.4
/styles.css?hash=a1b2c3d4e5f6

Si estás construyendo parámetros de caché que se generan dinámicamente a partir de hashes o cadenas de versión que pueden contener caracteres especiales, asegúrate de codificarlos antes de agregarlos. El Codificador/Decodificador de URL lo maneja rápidamente si estás probando o construyendo URLs manualmente.

Los tres errores que atacan a la mayoría de los desarrolladores

1. Usar no-cache cuando se quiere no-store. Si estás manejando respuestas de autenticación, puntos de salida de sesión o cualquier contenido con datos personales sensibles, necesitas no-store. no-cache deja los datos en el caché del navegador (solo marcados como obsoletos); no-store elimina completamente el rastro. La diferencia importa cuando los usuarios comparten dispositivos.

2. No establecer s-maxage para el control del CDN. Pega el contenido de tu .github/workflows/*.yml aquí s-maxage, tu CDN usa max-age. Si max-age es corto para la frescura del navegador (por ejemplo, 60 segundos), tu CDN almacena durante 60 segundos también — lo cual probablemente no sea lo que deseas. Separa explícitamente los dos TTLs.

3. public en endpoints que devuelven datos del usuario. Este es el incidente de seguridad, no solo un error de rendimiento. Cualquier respuesta que sea personalizada o autenticada debe ser private. Por defecto a private y opta por public solo para recursos verdaderamente compartidos.

Reunir todo lo anterior

El modelo mental: no-cache se refiere a la enfoque de frescura — la respuesta vive en el caché, pero necesita una validación del servidor antes de su uso. no-store se refiere a dejar sin rastro. max-age es tu TTL del navegador. s-maxage es tu TTL del CDN. Los ETags son lo que hacen que la revalidación sea barata.

Asegúrate de tener la private/public diferenciación correcta en cualquier endpoint que toque datos del usuario. Ese único error — copiar un encabezado de caché de un recurso estático a un endpoint autenticado — es el que se convierte en una fuga de datos entre usuarios cuando el CDN comienza a almacenar respuestas personalizadas.

¿Quieres eliminar publicidad? Adiós publicidad hoy

Instalar extensiones

Agregue herramientas IO a su navegador favorito para obtener acceso instantáneo y búsquedas más rápidas

añadir Extensión de Chrome añadir Extensión de borde añadir Extensión de Firefox añadir Extensión de Opera

¡El marcador ha llegado!

Marcador es una forma divertida de llevar un registro de tus juegos, todos los datos se almacenan en tu navegador. ¡Próximamente habrá más funciones!

ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?

Noticias Aspectos técnicos clave

Involucrarse

Ayúdanos a seguir brindando valiosas herramientas gratuitas

Invítame a un café
ANUNCIO · ¿ELIMINAR?