Cache-Control
Uso
Los servidores de origen, los intermediarios y los clientes se apoyan en Cache-Control para ponerse de acuerdo sobre cuándo una respuesta almacenada sigue siendo utilizable y cuándo hace falta una copia nueva. Una misma respuesta suele combinar varias directivas para expresar una política de caché completa: cuánto tiempo almacenar, quién tiene permitido almacenar y qué hacer una vez que expira la frescura.
La siguiente tabla muestra qué directivas se aplican a las solicitudes, a las respuestas o a ambas.
Varias directivas se separan con comas dentro de un único valor de cabecera, o bien se reparten entre varias cabeceras Cache-Control. Cuando aparecen directivas contradictorias, se aplica la combinación más restrictiva.
Nota
Las cachés ignoran las directivas que no reconocen. Esto permite introducir directivas nuevas sin romper las implementaciones más antiguas.
Nota
Cuando no hay cabecera Cache-Control, las cachés aplican una frescura heurística. Una heurística habitual es el 10 % del tiempo transcurrido desde Last-Modified. Esto significa que los navegadores y las CDN sí almacenan en caché las respuestas sin Cache-Control. Definir Cache-Control de forma explícita evita comportamientos de caché inesperados.
Nota
Cache-Control determina cuándo revalidar (el tiempo de vida de la frescura). ETag determina cómo revalidar (la identidad del contenido). Ambos funcionan en conjunto: Cache-Control decide si hace falta revalidar y ETag decide si el contenido ha cambiado. La cabecera Pragma es el equivalente en HTTP/1.0 de Cache-Control: no-cache y está en la práctica obsoleta.
max-age
La directiva max-age indica a las cachés que devuelvan una respuesta almacenada solo si esta no tiene más antigüedad que el número de segundos indicado. Los valores no válidos, como los números negativos, se tratan como 0.
Cache-Control: max-age=<seconds>
Definir max-age=0 fuerza una revalidación de extremo a extremo. Este patrón tiene su origen en las implementaciones de HTTP/1.0 que carecían de soporte para no-cache.
max-stale
La directiva max-stale señala que se acepta una respuesta cuyo Age ha superado el tiempo de vida de la frescura en hasta el número de segundos indicado. La ventana de tolerancia empieza una vez que expira max-age.
Cache-Control: max-stale=<seconds>
Esta directiva resulta útil cuando el servidor de origen está temporalmente inaccesible y se acepta una respuesta ligeramente obsoleta.
min-fresh
La directiva min-fresh solicita una respuesta almacenada cuyo tiempo de vida de frescura restante sea de al menos el número de segundos indicado. La caché devuelve la copia almacenada solo si la respuesta seguirá fresca durante ese periodo adicional.
Cache-Control: min-fresh=<seconds>
no-cache
Una solicitud que lleva no-cache exige que la caché valide la respuesta almacenada con el origen antes de entregar la copia. Esto fuerza la revalidación sin descartar la entrada almacenada.
Cache-Control: no-cache
Nota
Para impedir por completo que una caché almacene una respuesta, utilice no-store en su lugar.
no-store
La directiva no-store pide a las cachés que no almacenen la solicitud ni la respuesta correspondiente.
Cache-Control: no-store
no-transform
La directiva no-transform prohíbe a los intermediarios modificar el cuerpo de la respuesta, por ejemplo recomprimiendo imágenes o convirtiendo formatos multimedia. La restricción se aplica tanto si el intermediario es un proxy de caché como si es una pasarela de reenvío.
Cache-Control: no-transform
only-if-cached
La directiva only-if-cached indica a la caché que devuelva una respuesta almacenada sin contactar con el origen. Si no existe ninguna respuesta almacenada adecuada, la caché devuelve un estado 504.
Cache-Control: only-if-cached
max-age
La directiva max-age declara el número de segundos durante los cuales la respuesta permanece fresca tras su generación. El contador arranca en el momento en que el origen crea la respuesta, de modo que el tiempo de tránsito y el tiempo pasado en cachés intermedias se descuentan de ese presupuesto.
Cache-Control: max-age=<seconds>
Una respuesta con max-age=3600 se mantiene fresca durante una hora. Transcurrida esa hora, las cachés consideran obsoleta la respuesta y, según las demás directivas presentes, la revalidan u obtienen una copia nueva.
s-maxage
La directiva s-maxage (max-age compartido) anula max-age en las cachés compartidas, como las CDN y los servidores proxy. Las cachés privadas de los navegadores ignoran s-maxage y recurren a max-age.
Cache-Control: s-maxage=<seconds>
no-cache
La directiva no-cache en la respuesta exige que las cachés revaliden la respuesta almacenada con el origen antes de cada reutilización. La caché sigue almacenando la respuesta, lo que permite solicitudes condicionales con ETag o Last-Modified.
Cache-Control: no-cache
Cuando no-cache incluye una lista de nombres de campo, solo esas cabeceras concretas requieren revalidación. El resto de la respuesta almacenada se entrega sin contactar con el origen.
Cache-Control: no-cache="Set-Cookie"
Nota
Para impedir el almacenamiento por completo, utilice no-store.
no-store
La directiva no-store impide que cualquier caché almacene la respuesta. Todas las solicitudes posteriores van al origen.
Cache-Control: no-store
Nota
no-cache permite el almacenamiento, pero exige revalidar antes de cada uso. La caché comprueba con el origen mediante If-None-Match o If-Modified-Since y recibe un 304 si el contenido no ha cambiado. no-store impide el almacenamiento por completo, de modo que no se conserva ninguna copia y cada solicitud obtiene la respuesta completa. Un error habitual es usar no-cache cuando lo que se pretende es no-store para datos sensibles, como registros bancarios o médicos. no-cache es eficiente para contenido que se actualiza con frecuencia. no-store es para contenido que nunca debe quedar en disco.
no-transform
La directiva no-transform en la respuesta impide que los intermediarios alteren el cuerpo de la respuesta antes de reenviarla, almacenen o no el contenido en caché.
Cache-Control: no-transform
must-revalidate
La directiva must-revalidate permite a las cachés entregar la respuesta mientras esta siga fresca. Una vez obsoleta, la caché contacta con el origen para revalidarla antes de volver a entregarla. Si el origen está inaccesible, la caché devuelve un 504 en lugar de entregar contenido obsoleto.
Cache-Control: must-revalidate
proxy-revalidate
La directiva proxy-revalidate funciona exactamente igual que must-revalidate, salvo que el requisito se aplica únicamente a las cachés compartidas. Las cachés privadas de los navegadores no se ven afectadas.
Cache-Control: proxy-revalidate
must-understand
La directiva must-understand indica a una caché que almacene la respuesta solo cuando reconozca el código de estado y comprenda los requisitos de caché asociados.
Cache-Control: must-understand, no-store
Combinar must-understand con no-store proporciona una alternativa de respaldo: las cachés que no admiten must-understand ignoran la directiva desconocida y respetan no-store en su lugar.
private
La directiva private restringe el almacenamiento a las cachés privadas, normalmente el navegador del usuario final. Las cachés compartidas, como las CDN y los servidores proxy, descartan la respuesta.
Cache-Control: private
public
La directiva public marca una respuesta como apta para su almacenamiento en cachés compartidas. Las respuestas que llevan una cabecera Authorization no se almacenan en cachés compartidas salvo que esté presente la directiva public.
Cache-Control: public
Nota
La directiva public es innecesaria cuando ya están presentes must-revalidate o s-maxage.
immutable
La directiva immutable garantiza que el cuerpo de la respuesta no cambiará durante el tiempo de vida de la frescura. Las cachés omiten las solicitudes condicionales para los recursos inmutables, lo que elimina los viajes de ida y vuelta de revalidación para recursos como los paquetes de JavaScript versionados o las imágenes con huella digital.
Cache-Control: public, max-age=31536000, immutable
stale-while-revalidate
La directiva stale-while-revalidate amplía la ventana de uso de una respuesta obsoleta. Una vez expirada la frescura, las cachés entregan la copia obsoleta mientras revalidan en segundo plano. El parámetro define durante cuántos segundos adicionales sigue siendo aceptable la respuesta obsoleta.
Cache-Control: max-age=600, stale-while-revalidate=30
Cuando termina la revalidación en segundo plano, la caché sustituye la entrada obsoleta por la respuesta nueva. Este patrón oculta a los usuarios finales la latencia de la revalidación.
stale-if-error
La directiva stale-if-error permite a las cachés entregar una respuesta obsoleta cuando el origen devuelve un estado de error (500, 502, 503 o 504) o está inaccesible. El parámetro fija el número de segundos, más allá del tiempo de vida de la frescura, durante los cuales la respuesta obsoleta sigue siendo utilizable como alternativa de respaldo.
Cache-Control: max-age=600, stale-if-error=86400
Ejemplo
Un recurso estático servido con un tiempo de vida de frescura largo y la marca immutable. El navegador y cualquier caché compartida almacenan esta respuesta durante un año sin revalidarla.
Cache-Control: public, max-age=31536000, immutable
Una respuesta de API destinada únicamente al navegador que realiza la solicitud. La caché almacena la respuesta durante cinco minutos y la revalida antes de reutilizarla una vez obsoleta.
Cache-Control: private, max-age=300, must-revalidate
Una política orientada a la CDN que concede a la caché compartida una ventana de diez minutos, mientras que la caché del navegador recibe un minuto. Las respuestas obsoletas se entregan durante un máximo de 30 segundos mientras la CDN revalida en segundo plano.
Cache-Control: s-maxage=600, max-age=60, stale-while-revalidate=30
Googlebot y max-age
La infraestructura de rastreo de Google implementa un almacenamiento en caché HTTP heurístico. La directiva max-age ayuda a Googlebot a determinar la frecuencia de rerrastreo. Una página con un max-age largo se vuelve a obtener con menos frecuencia, mientras que no-cache indica cambios frecuentes de contenido y justifica un rastreo más frecuente. Para ciertos códigos de estado, las respuestas sin ninguna cabecera de caché son heurísticamente almacenables de forma predeterminada, por lo que los orígenes que quieran impedir el almacenamiento por completo deben enviar no-store de forma explícita. Bingbot envía Cache-Control: no-cache en sus solicitudes y se apoya en crawl-delay dentro de robots.txt y en IndexNow para regular el ritmo de rastreo.
Nota
Para obtener ayuda con SEO y almacenamiento en caché, póngase en contacto con los consultores SEO exempleados de Google de Search Brothers.
Diagnóstico
Los comportamientos de caché inesperados se deben a malentendidos sobre las directivas, a anulaciones de la CDN o a cabeceras contradictorias.
Se entrega contenido obsoleto pese a la directiva no-cache. La directiva no-cache no impide el almacenamiento. Las cachés almacenan la respuesta y la revalidan en cada reutilización. Para impedir el almacenamiento por completo, utilice no-store. Combine ambas cuando haya datos sensibles de por medio: Cache-Control: no-cache, no-store.
La CDN ignora las directivas de Cache-Control. Muchas CDN anulan el Cache-Control del origen con sus propias políticas. Cloudflare respeta de forma predeterminada las cabeceras del origen, pero las anula cuando hay una Page Rule o una Cache Rule activa. AWS CloudFront usa la cabecera del origen salvo que haya una política de caché con TTL personalizados asociada. Revise el panel de la CDN en busca de reglas de anulación antes de depurar la configuración del origen.
El contenido obsoleto persiste tras reducir max-age. Los nodos perimetrales de la CDN y las cachés de los navegadores conservan las respuestas hasta que expira el max-age original. Reducir el valor en el origen no purga las copias ya almacenadas en caché. Ejecute una purga en la CDN después de cambiar los tiempos de vida de la caché. En Cloudflare, purgue por URL o utilice una purga completa de la zona. En CloudFront, cree una invalidación para las rutas afectadas.
El navegador muestra la página antigua al navegar hacia atrás o adelante pese a no-store. La caché de navegación hacia atrás y adelante (bfcache) de Chrome, Firefox y Safari restaura el estado completo de la página desde la memoria, sorteando no-store. Este comportamiento es intencionado y no representa una violación de la caché. Inspeccione la cabecera Cache-Control en la pestaña Network de DevTools con “Disable cache” desmarcado para confirmar que la cabecera llega al navegador. Añadir escuchadores del evento unload desactiva la bfcache en algunos navegadores, pero degrada el rendimiento.
La cabecera Expires entra en conflicto con Cache-Control. Cuando ambas cabeceras están presentes, Cache-Control: max-age tiene prioridad sobre Expires. Elimine la cabecera Expires para evitar confusiones. En nginx:
expires off;
add_header Cache-Control "max-age=3600";
En Apache:
Header unset Expires
Header set Cache-Control "max-age=3600"
Diagnosticar las cabeceras de caché con curl y DevTools. Ejecute curl -I https://example.re para inspeccionar las cabeceras de respuesta procedentes del origen. Añada -H “Cache-Control: no-cache” para sortear las cachés de la CDN y llegar directamente al origen. En las DevTools del navegador, abra la pestaña Network, seleccione la solicitud y revise la sección Response Headers. Fíjese en las cabeceras Age, X-Cache y CF-Cache-Status para determinar si la respuesta provino de un nodo perimetral de la CDN o del origen.