Artículo
Caché HTTP: las tres configuraciones que uso casi siempre
Cache-Control, ETag y stale-while-revalidate sin la parte teórica. Tres casos que cubren casi cualquier sitio y un comando para comprobar que de verdad funcionan.
Llevo años viendo la misma escena: alguien abre la especificación de caché HTTP, ve la cantidad de directivas que hay y decide que ya lo mirará otro día. Lo entiendo. Pero la verdad es que, en la práctica, casi todo se resuelve con tres configuraciones. El resto de la especificación existe para casos raros que probablemente no tengas.
Estos son los tres casos y lo que pongo en cada uno.
Los assets con hash en el nombre
Si tu build genera ficheros tipo app.4f3a9c.js, tienes suerte: ese fichero no va a cambiar nunca.
Si cambia el contenido, cambia el nombre, así que no hay riesgo de servir una versión vieja.
Cache-Control: public, max-age=31536000, immutable
Un año de caché y ninguna revalidación. Lo de immutable es un detalle que a veces se olvida: evita
que el navegador haga siquiera la petición condicional cuando el usuario pulsa recargar, que es más
frecuente de lo que parece.
El HTML
Con el HTML pasa lo contrario. Tiene que reflejar el despliegue nuevo en cuanto sale, pero tampoco tiene sentido descargarlo entero cada vez si no ha cambiado nada.
Cache-Control: no-cache
ETag: "a1b2c3"
Lo que ocurre por debajo es que el navegador manda If-None-Match: "a1b2c3" y, si nada ha cambiado,
el servidor contesta con un 304 Not Modified sin cuerpo. Una petición pequeña y rápida en lugar de
la página entera.
Respuestas de API que pueden ir unos segundos atrasadas
Este es el caso que menos gente conoce y el que más alegrías da. Sirve para cualquier endpoint donde un desfase de un minuto no importe: un listado de productos, un contador de visitas, el tiempo que hace.
Cache-Control: public, max-age=60, stale-while-revalidate=600
Durante los primeros 60 segundos la respuesta sale de caché sin más. Entre el segundo 60 y el 660 se sigue sirviendo la copia antigua mientras se pide una nueva en segundo plano. El usuario nunca se queda esperando, y el servidor recibe como mucho una petición por minuto.
Para tenerlo a mano
| Contenido | Cabecera |
|---|---|
| Asset con hash | public, max-age=31536000, immutable |
| HTML | no-cache + ETag |
| API pública que tolera desfase | public, max-age=60, stale-while-revalidate=600 |
| Datos por usuario | private, no-cache |
| Datos sensibles | no-store |
Comprobar que de verdad se está cacheando
Configurar las cabeceras es la mitad del trabajo. La otra mitad es comprobar que la CDN hace lo que crees que hace:
curl -sI https://ejemplo.com/app.4f3a9c.js | grep -i 'cache-control\|etag\|age'
Fíjate en la cabecera Age. Indica cuántos segundos lleva esa respuesta en la caché intermedia. Si
siempre vale 0, la CDN no está guardando nada, y esto pasa más de lo que uno pensaría. En mi
experiencia suele ser una cookie que se cuela en la respuesta o un Vary demasiado amplio.