Evita solicitudes de red innecesarias con la caché HTTP

Recuperar recursos a través de la red es lento y costoso:

  • Las respuestas grandes requieren muchos viajes de ida y vuelta entre el navegador y el servidor.
  • Tu página no se cargará hasta que se descarguen por completo todos sus recursos críticos.
  • Si una persona accede a tu sitio con un plan de datos móviles limitado, cada solicitud de red innecesaria es un desperdicio de su dinero.

¿Cómo puedes evitar las solicitudes de red innecesarias? La caché HTTP del navegador es tu primera línea de defensa. No es necesariamente el enfoque más potente ni flexible, y tienes un control limitado sobre la vida útil de las respuestas almacenadas en caché, pero es eficaz, es compatible con todos los navegadores y no requiere mucho trabajo.

En esta guía, se muestran los conceptos básicos de una implementación eficaz de la caché HTTP.

Compatibilidad del navegador

En realidad, no existe una sola API llamada caché HTTP. Es el nombre general de una colección de APIs de la plataforma web. Esas APIs son compatibles con todos los navegadores:

Cache-Control

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

ETag

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

Last-Modified

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

Cómo funciona la caché HTTP

Todas las solicitudes HTTP que realiza el navegador primero se enrutan a la caché del navegador para verificar si hay una respuesta almacenada en caché válida que se pueda usar para entregar la solicitud. Si hay una coincidencia, la respuesta se lee de la caché, lo que elimina la latencia de la red y los costos de datos que genera la transferencia.

El comportamiento de la caché HTTP se controla mediante una combinación de encabezados de solicitud y encabezados de respuesta. En un caso ideal, tendrás control sobre el código de tu aplicación web (que determinará los encabezados de solicitud) y la configuración de tu servidor web (que determinará los encabezados de respuesta).

Consulta el artículo Almacenamiento en caché HTTP de MDN para obtener una descripción general conceptual más detallada.

Encabezados de solicitud: Usa los valores predeterminados (por lo general).

Hay varios encabezados importantes que se deben incluir en las solicitudes salientes de tu app web, pero el navegador casi siempre se encarga de configurarlos en tu nombre cuando realiza solicitudes. Los encabezados de solicitud que afectan la verificación de actualización, como If-None-Match y If-Modified-Since, aparecen según la comprensión que el navegador tiene de los valores actuales en la caché HTTP.

Esto es una buena noticia, ya que significa que puedes seguir incluyendo etiquetas como <img src="my-image.png"> en tu código HTML, y el navegador se encargará automáticamente de la caché HTTP por ti, sin esfuerzo adicional.

Encabezados de respuesta: Configura tu servidor web

La parte de la configuración de la caché HTTP que más importa son los encabezados que tu servidor web agrega a cada respuesta saliente. Los siguientes encabezados influyen en el comportamiento eficaz del almacenamiento en caché:

  • Cache-Control: El servidor puede mostrar una directiva Cache-Control para especificar cómo y durante cuánto tiempo el navegador y otras cachés intermedias deben almacenar en caché la respuesta individual.
  • ETag. Cuando el navegador encuentra una respuesta almacenada en caché vencida, puede enviar un token pequeño (por lo general, un hash del contenido del archivo) al servidor para verificar si el archivo cambió. Si el servidor muestra el mismo token, el archivo es el mismo y no es necesario volver a descargarlo.
  • Last-Modified: Este encabezado tiene el mismo propósito que ETag, pero usa una estrategia basada en el tiempo para determinar si un recurso cambió, a diferencia de la estrategia basada en el contenido de ETag.

Algunos servidores web tienen compatibilidad integrada para establecer esos encabezados de forma predeterminada, mientras que otros no los incluyen, a menos que los configures de forma explícita. Los detalles específicos de cómo configurar los encabezados varían mucho según el servidor web que uses. Debes consultar la documentación de tu servidor para obtener los detalles más precisos.

Para ahorrarte búsquedas, aquí tienes instrucciones para configurar algunos servidores web populares:

No se inhabilita el almacenamiento en caché de HTTP si se omite el encabezado de respuesta Cache-Control. En cambio, los navegadores adivinan de forma eficaz qué tipo de comportamiento de almacenamiento en caché es más adecuado para un tipo de contenido determinado. Es probable que quieras tener más control que el que ofrece, así que tómate el tiempo para configurar tus encabezados de respuesta.

¿Qué valores de encabezado de respuesta deberías usar?

Hay dos situaciones importantes que debes tener en cuenta cuando configures los encabezados de respuesta de tu servidor web.

Almacenamiento en caché de larga duración para URLs con versiones

Supongamos que tu servidor le indica a los navegadores que almacenen en caché un archivo CSS durante 1 año (Cache-Control: max-age=31536000), pero tu diseñador acaba de realizar una actualización de emergencia que debes implementar de inmediato. ¿Cómo se notifica a los navegadores que actualicen la copia almacenada en caché "inactiva" del archivo? No puedes, al menos no sin cambiar la URL del recurso.

Después de que el navegador almacena en caché la respuesta, se usa la versión almacenada en caché hasta que ya no esté actualizada, según lo determinen max-age o expires, o hasta que se expulse de la caché por algún otro motivo, por ejemplo, si el usuario borra la caché del navegador. Como resultado, es posible que diferentes usuarios usen versiones diferentes del archivo cuando se construye la página: los usuarios que acaban de recuperar el recurso usan la versión nueva, mientras que los usuarios que almacenaron en caché una copia anterior (pero aún válida) usan una versión anterior de su respuesta.

¿Cómo puedes obtener lo mejor de ambos mundos: la actualización rápida y la caché del cliente? Cambias la URL del recurso y obligas al usuario a descargar la respuesta nueva cada vez que cambia su contenido. Por lo general, para ello, se incorpora una huella digital del archivo o un número de versión en su nombre, por ejemplo, style.x234dff.css.

Cuando respondas solicitudes de URLs que contengan "huella digital" o información de control de versiones, y cuyo contenido nunca debe cambiar, agrega Cache-Control: max-age=31536000 a tus respuestas.

Si configuras este valor, le indicas al navegador que, cuando necesite cargar la misma URL en cualquier momento durante el próximo año (31,536,000 segundos, el valor máximo admitido), puede usar inmediatamente el valor de la caché HTTP, sin tener que realizar una solicitud de red a tu servidor web. ¡Genial! Obtuviste de inmediato la confiabilidad y la velocidad que se obtiene al evitar la red.

Las herramientas de compilación, como webpack, pueden automatizar el proceso de asignar huellas de hash a las URLs de tus recursos.

Revalidación del servidor para URLs sin versión

Lamentablemente, no todas las URLs que cargas tienen control de versiones. Tal vez no puedas incluir un paso de compilación antes de implementar tu app web, por lo que no puedes agregar hashes a las URLs de tus recursos. Además, cada aplicación web necesita archivos HTML, que (casi) nunca incluirán información de control de versiones, ya que nadie se molestará en usar tu app web si necesita recordar que la URL que debe visitar es https://example.com/index.34def12.html. Entonces, ¿qué puedes hacer con esas URLs?

Esta es una situación en la que debes admitir la derrota. La caché HTTP por sí sola no es lo suficientemente potente como para evitar la red por completo. (No te preocupes, pronto aprenderás sobre los servicios en primer plano, que nos brindarán la asistencia que necesitamos para que la batalla vuelva a tu favor). Sin embargo, hay algunos pasos que puedes seguir para asegurarte de que las solicitudes de red sean lo más rápidas y eficientes posible.

Los siguientes valores de Cache-Control pueden ayudarte a definir mejor dónde y cómo se almacenan en caché las URLs sin versión:

  • no-cache. Esto le indica al navegador que debe volver a validarse con el servidor cada vez que usa una versión almacenada en caché de la URL.
  • no-store. Esto le indica al navegador y a otras cachés intermedias (como las CDN) que nunca deben almacenar ninguna versión del archivo.
  • private. Los navegadores pueden almacenar en caché el archivo, pero las cachés intermedias no.
  • public. Cualquier caché puede almacenar la respuesta.

Consulta el Apéndice: Flujo de trabajo de Cache-Control para visualizar el proceso de decisión sobre qué valores de Cache-Control usar. Cache-Control también puede aceptar una lista de directivas separadas por comas. Consulta el Apéndice: Ejemplos de Cache-Control.

También puede ser útil establecer ETag o Last-Modified. Como se menciona en Encabezados de respuesta, ETag y Last-Modified cumplen el mismo propósito: determinar si el navegador debe volver a descargar un archivo almacenado en caché que venció. Te recomendamos que uses ETag porque es más precisa.

Supongamos que transcurrieron 120 segundos desde la recuperación inicial y que el navegador inició una solicitud nueva para el mismo recurso. Primero, el navegador verifica la caché HTTP y encuentra la respuesta anterior. Lamentablemente, el navegador no puede usar la respuesta anterior porque ya venció. En este punto, el navegador podría enviar una solicitud nueva y recuperar la nueva respuesta completa. Sin embargo, eso no es eficiente porque, si el recurso no cambió, no hay razón para descargar la misma información que ya está en la caché.

Ese es el problema que los tokens de validación, como se especifica en el encabezado ETag, están diseñados para resolver. El servidor genera y muestra un token arbitrario, que suele ser un hash o alguna otra huella digital del contenido del archivo. El navegador no necesita saber cómo se genera la huella digital; solo debe enviarla al servidor en la siguiente solicitud. Si la huella digital sigue siendo la misma, significa que el recurso no cambió y el navegador puede omitir la descarga.

Configurar ETag o Last-Modified hace que la solicitud de nueva validación sea mucho más eficiente, ya que le permite activar los encabezados de solicitud If-Modified-Since o If-None-Match que se mencionan en Encabezados de solicitud.

Cuando un servidor web configurado correctamente ve esos encabezados de solicitud entrantes, puede confirmar si la versión del recurso que el navegador ya tiene en su caché HTTP coincide con la versión más reciente del servidor web. Si hay una coincidencia, el servidor puede responder con una respuesta HTTP 304 Not Modified, que es el equivalente a "Hey, sigue usando lo que ya tienes". Cuando se envía este tipo de respuesta, hay muy pocos datos para transferir, por lo que suele ser mucho más rápido que tener que enviar una copia del recurso que se solicita.

Visualización de un cliente que solicita un recurso y el servidor que responde con un encabezado 304.
El navegador solicita /file al servidor y, además, incluye el encabezado If-None-Match para indicarle al servidor que solo muestre el archivo completo si el ETag del archivo en el servidor no coincide con el valor If-None-Match del navegador. En este caso, los 2 valores coincidieron, por lo que el servidor muestra una respuesta 304 Not Modified con instrucciones sobre cuánto tiempo más se debe almacenar en caché el archivo (Cache-Control: max-age=120).

Resumen

La caché HTTP es una forma eficaz de mejorar el rendimiento de la carga, ya que reduce las solicitudes de red innecesarias. Es compatible con todos los navegadores y no requiere mucho trabajo para configurarlo.

Las siguientes configuraciones de Cache-Control son un buen punto de partida:

  • Cache-Control: no-cache para los recursos que se deben volver a validar con el servidor antes de cada uso.
  • Cache-Control: no-store para los recursos que nunca deben almacenarse en caché.
  • Cache-Control: max-age=31536000 para recursos con versión.

Además, el encabezado ETag o Last-Modified puede ayudarte a volver a validar los recursos de caché vencidos de forma más eficiente.

Más información

Si quieres ir más allá de los conceptos básicos del uso del encabezado Cache-Control, consulta la guía Prácticas recomendadas de almacenamiento en caché y errores de la edad máxima de Jake Archibald.

Consulta Ama tu caché para obtener orientación sobre cómo optimizar el uso de la caché para los visitantes recurrentes.

Apéndice: Más sugerencias

Si tienes más tiempo, aquí tienes otras formas en las que puedes optimizar el uso de la caché HTTP:

  • Usa URLs coherentes. Si publicas el mismo contenido en diferentes URLs, ese contenido se recuperará y almacenará varias veces.
  • Minimiza la deserción. Si parte de un recurso (como un archivo CSS) se actualiza con frecuencia, mientras que el resto no (como el código de la biblioteca), considera dividir el código que se actualiza con frecuencia en un archivo independiente y usar una estrategia de almacenamiento en caché de corta duración para el código que se actualiza con frecuencia y una estrategia de almacenamiento en caché de larga duración para el código que no cambia con frecuencia.
  • Consulta la nueva directiva stale-while-revalidate si se acepta algún grado de inactividad en tu política de Cache-Control.

Apéndice: Diagrama de flujo de Cache-Control

Diagrama de flujo
El proceso de decisión para configurar tus encabezados Cache-Control.

Apéndice: Ejemplos de Cache-Control

Valor Cache-Control Explicación
max-age=86400 Los navegadores y las cachés intermedias pueden almacenar en caché la respuesta hasta por 1 día (60 segundos × 60 minutos × 24 horas).
private, max-age=600 El navegador puede almacenar en caché la respuesta (pero no las cachés intermedias) durante un máximo de 10 minutos (60 segundos × 10 minutos).
public, max-age=31536000 Cualquier caché puede almacenar la respuesta durante 1 año.
no-store La respuesta no se puede almacenar en caché y se debe recuperar por completo en cada solicitud.