HTTP caching es un mecanismo del protocolo HTTP que permite a navegadores, CDNs y proxies almacenar copias de respuestas y reutilizarlas en peticiones posteriores sin tocar el servidor de origen. Es la tecnica de rendimiento mas importante de la web. Un activo estatico bien cacheado (imagen, CSS, JS) tarda 1 a 10 ms desde el cache del navegador frente a 100 a 1000 ms desde el origen. Se controla con cabeceras definidas en RFC 7234 (junio 2014) y RFC 9111 (junio 2022): Cache-Control (principal moderno), Expires (legacy), ETag y Last-Modified (validadores) y Vary (clave de cache). Usado bien reduce LCP, ahorra ancho de banda (Google estima 60 a 80 por ciento cacheable), reduce carga del origen y baja huella de carbono. Mal usado provoca contenido obsoleto, despliegues rotos y recargas infinitas.
Como funciona
- Cache hit si la copia esta fresca.
- Conditional request con If-None-Match o If-Modified-Since si esta caducada pero hay validador, respuesta 304 Not Modified.
- Cache miss si no hay validador.
Cache-Control
| Directiva | Significado |
|---|---|
max-age=N | Fresca durante N segundos. |
s-maxage=N | Solo caches compartidos. |
public | Cualquier cache puede guardar. |
private | Solo el navegador. |
no-cache | Revalidar antes de usar. |
no-store | No almacenar nunca. |
must-revalidate | Sin servir stale en error. |
stale-while-revalidate=N | Sirve stale mientras revalida. |
stale-if-error=N | Sirve stale si origen falla. |
immutable | Nunca cambiara. |
Cache-Control: public, max-age=31536000, immutable
Cache-Control: public, max-age=0, s-maxage=300, stale-while-revalidate=86400
Cache-Control: private, no-cache
Cache-Control: no-storeETag
Identificador opaco (a menudo hash). El cliente envia If-None-Match. Si coincide, 304 sin cuerpo. Pueden ser strong o weak (prefijo W/).
Last-Modified
Marca temporal con resolucion de 1 segundo. If-Modified-Since al volver. ETag es mejor para cambios mas frecuentes.
Vary
Vary: Accept-Encodingsepara gzip/brotli.Vary: Accept-Languagesepara idiomas.Vary: User-Agentcasi siempre malo.Vary: Cookierompe el cache compartido.
Browser vs CDN vs Proxy
| Capa | Ubicacion | Honora |
|---|---|---|
| Navegador | Dispositivo del usuario | max-age, ETag, Last-Modified |
| CDN edge | PoP cercano (Cloudflare, Fastly, Akamai, CloudFront) | s-maxage, stale-while-revalidate |
| Proxy corporativo | Redes empresariales | public, private |
| Service Worker | Pagina via JS | Logica propia |
Cache busting y fingerprinting
webpack, Vite, esbuild, Turbopack, Rollup. app.css -> app.a1b2c3d4.css. HTML con max-age corto, assets con hash con max-age=31536000 immutable.
HTTP caching en WordPress
- WP Rocket.
- LiteSpeed Cache.
- W3 Total Cache.
- WP Super Cache.
- Cloudflare APO a 5 USD/mes.
location ~* \.(jpg|jpeg|png|gif|webp|avif|svg|ico|css|js|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}Errores comunes
- max-age largo en HTML.
- Sin headers en activos estaticos.
- Vary: User-Agent.
- Set-Cookie con public.
- Pragma: no-cache (obsoleto).
- Sin headers (heuristica del navegador).
- Cache poisoning sin Vary correcto.
Como probarlo
- DevTools Network.
curl -I.- WebPageTest.
- Lighthouse.
- RedBot (redbot.org).
HTTP/2 y HTTP/3
Misma semantica de cache. Server Push deprecado en Chrome desde 2022 en favor de Early Hints (RFC 8297, 103 Early Hints).
Como ayuda InspectWP?
InspectWP comprueba Cache-Control, ETag, Last-Modified y Vary de cada activo. Marca cabeceras faltantes, max-age cortos en activos con hash y combinaciones Vary peligrosas.