Performance · 7 min lettura

Come funziona la cache del browser e come ottimizzarla

La cache HTTP è uno degli strumenti più efficaci per velocizzare un sito web. Configurata bene, evita download inutili e migliora drasticamente i tempi di caricamento per i visitatori di ritorno.

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

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-cacheVerifica sempre
CSS/JS (con hash nel nome)max-age=31536000, immutable1 anno
Immagini statichemax-age=259200030 giorni
Font webmax-age=31536000, immutable1 anno
API/dati JSONno-store o breve max-ageDipende 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

Come svuotare la cache del browser?

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.

Cosa fa no-cache vs no-store?

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.

La cache CDN è diversa dalla cache del browser?

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.

Header HTTP di cache: guida pratica

Il comportamento della cache si controlla con gli header HTTP di risposta. Cache-Control: max-age=N — l'asset è fresco per N secondi (es. max-age=31536000 = 1 anno per asset con hash nel nome). Cache-Control: no-cache — l'asset va rivalidato ad ogni richiesta (il browser mantiene una copia ma chiede sempre al server se è ancora valida). Cache-Control: no-store — nessuna cache, l'asset viene sempre riscaricato (per contenuti sensibili come pagine bancarie). ETag: hash del contenuto del file — il browser invia If-None-Match: "hash" al server e riceve 304 Not Modified se non è cambiato. Last-Modified: data di ultima modifica — funziona come ETag ma meno preciso (granularità al secondo).

Cache busting: come forzare l'aggiornamento

Il problema classico: hai deployato una nuova versione del CSS ma gli utenti vedono ancora la versione vecchia in cache. La soluzione è il cache busting — cambiare il nome o URL dell'asset ad ogni deploy. Strategie: hash nel nome file (styles.a3b4c5.css) — automatico con Webpack/Vite, massimo controllo; query string (styles.css?v=2.1.0) — semplice ma alcuni proxy non cachano URL con query string; versione nel path (/v2/styles.css) — pulito ma richiede redirect per versioni vecchie. Per HTML e API, usa Cache-Control: no-cache — sempre rivalidato ma usando la cache se non cambiato (304).

Service Worker e cache programmabile

I Service Worker permettono di controllare la cache con JavaScript per applicazioni Progressive Web App (PWA). Strategie comuni: Cache First — serve dalla cache, aggiorna in background (per asset statici); Network First — prova la rete, fallback sulla cache (per dati dinamici); Stale While Revalidate — serve la cache immediatamente e aggiorna in background (per contenuti quasi-statici come feed news). Il Workbox di Google semplifica l'implementazione di queste strategie senza codice boilerplate.

#
Hash Generator
Calcola hash per cache busting e verifica integrità file.
Usa il tool →
HTTP Request Builder
Testa header di cache (ETag, Cache-Control) su qualsiasi API.
Usa il tool →