Cache de navegador y cache compartida

11 de abril de 2021

La cache del navegador es uno de los recursos más potentes para mejorar la percepción del usuario con respecto al rendimiento de la web.

Se trata de copias de todos o parte de los recursos necesarios para el uso de la web que se almacenan en el navegador del visitante con la intención de ser reutilizados y no tener que descargarse cada vez. Es la bendición para los usuarios, y, en ocasiones un rompedero de cabeza para los desarrolladores. Ya escribí sobre cómo borrar la cache en algunos navegadores.

Hoy, quiero intentar resumir las «opciones de configuración» que podemos proponerle a los distintos niveles de cache, porque, sí, existen varios niveles en los que nuestra web puede ser cacheada.

Cache en el navegador

Se trata de la cache en el navegador del propio usuario que consume nuestro contenido. Veremos que conforme las cabeceras, podríamos llamarle cache privada.

Cache en el proxy o CDN

Se trata de una cache en un servicio intermedio, creo que se suele llamar cache compartida o shared cache. Típicamente, podemos pensar en un CDN (Content Delivery Network) o un proxy. Ambos, almacenan una copia de los recursos de la web para servirlos sin necesidad de «molestar» al servidor de origen. O bien, como una forma de acercar, los recursos al consumidor, de forma que se agiliza la navegación.

Y para la configuración,
«HOW THEY DO IT?»

La configuración de la gestión del comportamiento de los diferentes niveles de cache se realiza mediante el uso de cabeceras HTTP. En ellas establecemos valores como: cuánto tiempo se puede almacenar cierto recurso, quién puede almacenarlo, o si debe, o no, revalidar las versiones almacenadas con el servidor principal.

Estas cabeceras se pueden insertar en el propio código de la aplicación web, en un fichero .htaccess o similar, o en la propia configuración del servidor. En el caso de WordPress, muchos plugins de optimización y cache ofrecen distintas combinaciones para configurar estas cabeceras, pero, realmente, la mayoría de las veces, no comprendía muy bien lo que significaba elegir unas u otras opciones.

Entendiendo browser-cache

Veamos estas cabeceras, e intentemos comprender para qué sirven.

Expires

Contiene la fecha y hora hasta la cual el fichero es considerado válido. Esta cabecera se ignora si está establecido max-age en Cache Control.

ETag

ETag (Entity Tag) es una cadena que sirve como token de validación para ficheros cacheados. Normalmente es un hash del fichero en cuestión.

Una vez que el tiempo de caché para un fichero ha expirado, usa este token para comparar la versión cacheada con la almacenada en el servidor.

Para esto, se envía el token junto con la petición del fichero al servidor. Si la copia no ha variado, el servidor responde con un código 304 (Not Modified); Si el servidor encuentra que la copia está obsoleta, responderá enviando la copia actualizada del fichero.

Cache-Control

Comportamiento del cache:

  • Cache-Control: public → Cualquiera puede cachear el fichero (navegador, CDN, proxy…)
  • Cache-Control: private → El fichero solo debe ser cacheado por un cliente final, generalmente, un navegador web del usuario.
  • Cache-Control: no-store → Le dice al cliente que no guarde cache y que siempre pida el recurso al servidor.
  • Cache-Control: no-cache → Es un poco confuso. No le dice al cliente que no cachee, sino que le pide que valide las versiones cacheadas con el servidor antes de usarlas. Esto lo consigue con las cabeceras ETag.

Por compatibilidad con caches HTTP/1.0, a veces puedes encontrar la cabecera pragma, pero está en desuso desde HTTP/1.1.

Expiración

  • Cache-Control: max-age=300 → Especifica el tiempo, en segundos, que un fichero debería ser cacheado.
  • Cache-Control: s-max-age=300 → Este lo usan caches intermedias, como los CDN.

Validación

  • Cache-Control: must-revalidate → La cache debe ser revalidada y los ficheros expirados no deben ser usados.
  • Cache-Control: proxy-revalidate → Igual que la anterior, pero solo es aplicada en caches intermedias. Los navegadores la ignoran.

Last-Modified

Contiene la fecha y hora en la que el fichero se ha modificado.

Más sobre este tema en: https://medium.com/@codebyamir/a-web-developers-guide-to-browser-caching-cc41f3b73e7c

Cada web es un mundo, con todo esto en mente, yo diría que:

  • Ficheros de fuentes, imágenes, bibliotecas, como jQuery, ficheros de Bootstrap… No parece descabellado pedir que se mantengan hasta por un año:
Cache-Control: public, max-age=31536000
Lenguaje del código: PHP (php)
  • Hojas de estilos, javaScript propios, HTML:
Cache-Control: no-cache
Lenguaje del código: HTTP (http)
  • Si el sitio es muy maduro, y no se prevén cambios en diseño y comportamiento, creo que podemos establecer un tiempo, se me ocurre un día, de cache para hojas de estilo y js:
Cache-Control: public, max-age=86400
Lenguaje del código: PHP (php)

Es mi opinión, PageSpeed Insights, por ejemplo, opina que un día es poco tiempo para la caché. Pero, sinceramente, ¿la mayoría tus visitantes vuelven cada día a ver tu web?

Aquí entran en juego otras estrategias, por ejemplo: ¿Es un ecommerce? ¿Cómo suele ser el camino hacia la conversión/venta? Desde que el usuario visita la web, por primera vez, hasta que realiza la compra ¿cuánto tiempo suele pasar? ¿Una semana? ¿Dos? En ese tiempo ¿Suele haber cambios en diseños o comportamientos? Cuando los hay, ¿qué importancia tienen? ¿Es necesario que el navegador del usuario descarte automáticamente la cache que tiene, o puede esperar a que caduque la cache para traerse los nuevos cambios?

Como todo, la configuración de la cache tiene su parte buena y su parte menos buena. Cuantos más recursos estén cacheados, más eficaz y rápida será; pero, a la hora de aplicar posibles cambios, más tiempo tardarán los usuarios en apreciarlos. Y viceversa, una caché que deba revalidar los recursos una y otra vez, será menos eficaz, pero los usuarios podrán ver los cambios más rápidamente.

Aunque, en la página que mozilla dedica a la cache de navegadores, aparecen algunos parámetros más, creo que con estos he tocado los más importantes.

Uso de parámetros GET de versión

Una de las formas de forzar la actualización de un fichero cacheado por su versión más moderna es añadiendo un parámetro GET de versión al nombre del recurso, obteniendo urls como: https://midominio.tld/styles/style.css?version=1.0.

Creo haber leído que en algunos navegadores, esto desincentiva el cacheo de recursos y, en más de una ocasión, me encuentro con la recomendación de no usarlo o, directamente, eliminar esta opción.

Ciertamente, esto es válido si, programáticamente, se va actualizando el número de versión con cada cambio en el fichero, pero si olvidamos actualizar la versión, puede ser un dolor de cabeza. En algún lugar, encontré una posible solución que se trata de usar un timestamp de la última modificación como número de versión. En PHP, por ejemplo, con algo como:

<?php $datetime_modified = filemtime('/style.css'); ?> <?php echo '<link href="/style.css" . $datetime_modified . '" rel="stylesheet" [...] />'; ?>
Lenguaje del código: HTML, XML (xml)

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.