Caché HTTP: caché fuerte, negociado y estrategias de CDN

Web/SEO

Caché HTTP: la primera línea de defensa de la optimización del rendimiento

Una configuración de caché adecuada puede lograr cero solicitudes de red en el segundo acceso, reduciendo el tiempo de carga de segundos a milisegundos.

Tipo de caché Mecanismo ¿Solicita al servidor? Velocidad
Caché fuerte Cache-Control / Expires No La más rápida (0ms)
Caché negociado ETag / Last-Modified Sí (petición condicional) Rápida (respuesta 304)
Sin caché no-cache / no-store Sí (petición completa) La más lenta

I. Caché fuerte

Directivas Cache-Control

Cache-Control: max-age=31536000, immutable
Directiva Función Escenario aplicable
max-age=N Cachear N segundos Recursos estáticos
s-maxage=N CDN cachea N segundos (sobreescribe max-age) Escenarios CDN
immutable No revalidar incluso si expira Nombres de archivo con hash
public Permitir caché intermedio CDN
private Solo caché del navegador Contenido personalizado del usuario
no-cache Debe verificar antes de cada uso Páginas HTML
no-store No cachear nada Datos sensibles
must-revalidate Debe verificar después de expirar Respuestas API
stale-while-revalidate=N Devolver valor antiguo tras expirar, actualizar en segundo plano Actualización progresiva

Expires (estándar antiguo)

Expires: Thu, 02 Jun 2027 00:00:00 GMT

Prioridad: Cache-Control: max-age > Expires.


II. Caché negociado

ETag / If-None-Match

# Primera petición
GET /api/data
→ 200 OK
  ETag: "abc123"
  Cache-Control: max-age=0

# Petición siguiente (condicional)
GET /api/data
If-None-Match: "abc123"
→ 304 Not Modified  (sin cuerpo de respuesta, ahorra ancho de banda)

Last-Modified / If-Modified-Since

# Primera petición
GET /style.css
→ 200 OK
  Last-Modified: Mon, 01 Jun 2026 12:00:00 GMT

# Petición siguiente
GET /style.css
If-Modified-Since: Mon, 01 Jun 2026 12:00:00 GMT
→ 304 Not Modified

ETag vs Last-Modified

Dimensión ETag Last-Modified
Precisión Nivel de byte Nivel de segundo
Rendimiento Requiere cálculo de hash Lectura directa del tiempo del archivo
Fiabilidad Alta Baja (múltiples modificaciones en 1 segundo se pierden)
Distribuido Debe garantizar hash consistente Naturalmente consistente

Recomendación: Priorizar ETag.


III. Matriz de estrategias de caché

Páginas HTML

Cache-Control: no-cache

HTML es el archivo de entrada, debe verificarse cada vez para asegurar que los usuarios obtengan la última versión.

Recursos estáticos con Hash

Cache-Control: max-age=31536000, immutable

El nombre del archivo contiene Hash (ej., app.abc123.js), cuando el contenido cambia, el Hash cambia → la URL cambia → nueva petición. La URL antigua nunca cambia, se puede cachear un año y marcar como immutable.

Recursos estáticos sin Hash

Cache-Control: max-age=86400, stale-while-revalidate=604800

Tras expirar, primero devuelve el valor antiguo, actualiza silenciosamente en segundo plano, imperceptible para el usuario.

Respuestas API

Cache-Control: private, max-age=0, must-revalidate

Las respuestas API suelen contener datos de usuario, private prohíbe caché CDN, must-revalidate asegura que no se devuelvan valores antiguos tras expirar.


IV. Cabecera Vary: extensión de la clave de caché

Vary: Accept-Encoding, Accept-Language

Vary indica a la caché: además de la URL, debe distinguir versiones de caché según los valores de estas cabeceras de petición.

Valor Vary Significado Escenario
Accept-Encoding Cachear por método de compresión gzip vs br
Accept-Language Cachear por idioma Sitios multilingües
Cookie Cachear por Cookie Páginas personalizadas
* Cada petición con caché independiente Equivale a no cachear

Nota: Vary: Cookie causa una tasa de acierto de caché muy baja, usar con precaución.


V. Estrategia de caché CDN

Control de recuperación de origen

# CDN cachea 1 día, navegador cachea 5 minutos
Cache-Control: public, s-maxage=86400, max-age=300
Escenario s-maxage max-age Descripción
Recursos estáticos 31536000 31536000 CDN y navegador con caché larga
Respuestas API 300 0 CDN cachea 5 minutos, navegador no cachea
HTML 60 0 CDN cachea 1 minuto, navegador no cachea
Contenido personalizado — 0 CDN no cachea, navegador no cachea

Refresco de caché CDN

Método Velocidad Aplicable
Precalentamiento de URL Rápido Nuevo contenido publicado
Refresco completo Lento Corrección urgente
Refresco de directorio Medio Actualización por lotes
Cache-Control: no-cache Automático Escenarios API

Stale-While-Revalidate en la práctica

Cache-Control: max-age=60, stale-while-revalidate=86400
Segundo 0: Petición → Caché MISS → Recuperar origen → Devolver valor fresco
Segundo 30: Petición → Caché HIT → Devolver valor en caché
Segundo 90: Petición → Caché STALE → Devolver valor antiguo inmediatamente + recuperar origen en segundo plano
Segundo 91: Recuperación de origen completada → Caché actualizada
Segundo 120: Petición → Caché HIT → Devolver valor nuevo

Efecto: El usuario nunca espera la recuperación de origen, actualización silenciosa en segundo plano.


VI. Estrategia de invalidación de caché

Hash de contenido (recomendado)

<!-- Hash generado en tiempo de compilación -->
<script src="/app.abc123.js"></script>
<link href="/style.def456.css">
// Configuración webpack
output: {
  filename: '[name].[contenthash:8].js',
}

Parámetro de consulta de versión

<!-- Simple pero CDN puede no cachear parámetros ?v= -->
<script src="/app.js?v=2.0.0"></script>

Problema: Algunos CDN ignoran los parámetros de consulta, causando que la caché no se actualice.

Marca de tiempo (no recomendado)

<!-- Cambia cada vez, destruye completamente la caché -->
<script src="/app.js?t=1717315200"></script>

VII. Caché de Service Worker

Estrategia Cache First

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then(cached => cached || fetch(event.request))
  );
});

Estrategia Stale While Revalidate

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.open('dynamic').then(cache =>
      cache.match(event.request).then(cached => {
        const fetchPromise = fetch(event.request)
          .then(response => {
            cache.put(event.request, response.clone());
            return response;
          });
        return cached || fetchPromise;
      })
    )
  );
});

Selección de estrategia de caché

Estrategia Origen prioritario Aplicable
Cache First Caché Fuentes, imágenes
Network First Red API, HTML
Stale While Revalidate Caché + actualización en segundo plano CSS, JS
Network Only Red Peticiones no GET
Cache Only Caché Páginas offline

VIII. Depuración de caché

Chrome DevTools

  1. DevTools → Panel Network
  2. Ver columna Size:
    • from disk cache: Acierto en caché de disco
    • from memory cache: Acierto en caché de memoria
    • Tamaño real: Sin acierto
  3. Ver cabecera de respuesta Age: Tiempo que lleva en caché
  4. Marcar Disable cache: Deshabilitar caché (cuando DevTools está abierto)

Verificación con curl

# Ver cabeceras de respuesta
curl -I https://example.com/style.css

# Enviar petición condicional
curl -I -H 'If-None-Match: "abc123"' https://example.com/style.css
# 304 indica caché negociado acertado

# Simular diferente Accept-Encoding
curl -I -H 'Accept-Encoding: br' https://example.com/style.css

IX. Lista de mejores prácticas

  1. HTML: no-cache, asegurar que la entrada siempre es la más reciente
  2. JS/CSS con Hash: max-age=1 año + immutable
  3. API: must-revalidate, debe verificar tras expirar
  4. CDN: s-maxage para controlar la frecuencia de recuperación de origen
  5. Vary: Accept-Encoding, distinguir métodos de compresión
  6. Usar ETag en lugar de Last-Modified
  7. stale-while-revalidate para actualización imperceptible
  8. Service Worker para complementar capacidades offline
#HTTP缓存#Cache-Control#ETag#CDN#性能优化