Come funziona la cache del browser
Quando un browser scarica una risorsa (immagine, CSS, JS), può salvarla localmente per riutilizzarla nelle visite successive senza scaricarla di nuovo. Questo processo è controllato dagli header HTTP che il server invia insieme alla risorsa.
Ogni risorsa può avere una "scadenza": prima della scadenza il browser usa la versione locale senza nemmeno contattare il server. Dopo la scadenza, verifica se la versione sul server è cambiata.
L'header Cache-Control
L'header più importante per la cache è Cache-Control:
Cache-Control: max-age=31536000, immutable
Le direttive principali
max-age=N— la risorsa è valida per N secondi dalla rispostano-cache— riconvalida sempre con il server prima di usare la cacheno-store— non memorizzare mai in cache (dati sensibili)immutable— la risorsa non cambierà mai durante max-age (ottimizzazione aggressiva)stale-while-revalidate=N— usa la versione scaduta per N secondi mentre ricarica in backgroundpublic— la risorsa può essere salvata da CDN e proxy intermediprivate— solo il browser dell'utente può salvare (non CDN)
ETag: verifica delle modifiche
Quando una risorsa scade, il browser non la scarica subito: chiede al server se è cambiata. L'ETag è un identificatore univoco del contenuto del file (come un checksum):
# Prima risposta del server: ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" # Richiesta successiva del browser: If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4" # Se il file non è cambiato, il server risponde: HTTP/1.1 304 Not Modified ← nessun body, solo headers!
Il 304 Not Modified è molto efficiente: il server risponde con pochi byte di header invece di inviare di nuovo l'intero file.
Strategia ottimale per tipo di risorsa
| Tipo risorsa | Cache-Control consigliato | Durata |
|---|---|---|
| HTML (pagine) | no-cache | Verifica sempre |
| CSS/JS (con hash nel nome) | max-age=31536000, immutable | 1 anno |
| Immagini statiche | max-age=2592000 | 30 giorni |
| Font web | max-age=31536000, immutable | 1 anno |
| API/dati JSON | no-store o breve max-age | Dipende dai dati |
Cache busting: aggiornare i file con cache lunga
Se hai un CSS con cache di 1 anno e vuoi forzare l'aggiornamento, usa il cache busting: aggiungi un hash del contenuto al nome del file.
<!-- Senza cache busting (problematico) --> <link rel="stylesheet" href="/style.css"> <!-- Con cache busting (corretto) --> <link rel="stylesheet" href="/style.abc123de.css">
Webpack, Vite e altri bundler moderni generano automaticamente questi hash. Quando il file cambia, cambia il nome e il browser scarica la nuova versione.
Configurazione Apache e Nginx
Apache (.htaccess)
<IfModule mod_expires.c> ExpiresActive On ExpiresByType image/webp "access plus 1 month" ExpiresByType text/css "access plus 1 year" ExpiresByType application/javascript "access plus 1 year" ExpiresByType text/html "access plus 0 seconds" </IfModule>
Nginx
location ~* \.(css|js|woff2)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location ~* \.(jpg|png|webp|avif)$ {
add_header Cache-Control "public, max-age=2592000";
}
location ~* \.html$ {
add_header Cache-Control "no-cache";
}
FAQ
In Chrome/Firefox: Ctrl+Shift+Delete (o Cmd+Shift+Delete su Mac). Per fare un hard reload senza svuotare tutta la cache usa Ctrl+Shift+R o tieni premuto Shift cliccando il pulsante di ricarica.
no-cache significa "salvalo in cache ma verifica sempre se è aggiornato prima di usarlo". no-store significa "non salvarlo affatto". Per dati sensibili (es. home banking) usa no-store.
Sì. La cache del browser è locale al dispositivo dell'utente. La cache CDN è sui server della CDN, geograficamente vicini all'utente. Usa public per permettere la CDN cache, private per permettere solo la cache del browser.