Cos'e HTTP 304 Not Modified
Il codice HTTP 304 Not Modified e una risposta del server che indica al client: "la risorsa che stai chiedendo non e cambiata dall'ultima volta, usa pure quella che hai già in cache". E un meccanismo fondamentale del caching HTTP: il server non rispedisce il body, risparmiando banda e tempo di trasferimento.
Conditional requests
Il 304 viene emesso in risposta a richieste condizionali del client, che usano due header chiave:
- If-None-Match: il client invia l'ETag che ha in cache.
- If-Modified-Since: il client invia la data dell'ultima modifica nota.
Se la risorsa attuale corrisponde, il server risponde 304 senza body. Altrimenti 200 con il nuovo contenuto.
ETag (Entity Tag)
L'ETag e un'identificatore unico della rappresentazione corrente di una risorsa, calcolato dal server. Tipicamente un'hash MD5 o SHA del contenuto:
HTTP/1.1 200 OK
ETag: "5e8c3f7a-1f4"
Content-Type: text/html
...body...
Successive richieste dal client:
GET /page HTTP/1.1
If-None-Match: "5e8c3f7a-1f4"
Se ETag corrente == "5e8c3f7a-1f4": il server risponde 304 senza body. Altrimenti 200 con nuovo body e nuovo ETag.
Last-Modified e If-Modified-Since
Approccio alternativo basato su timestamp:
HTTP/1.1 200 OK
Last-Modified: Mon, 29 Jun 2026 10:00:00 GMT
# Client successivamente invia:
GET /page HTTP/1.1
If-Modified-Since: Mon, 29 Jun 2026 10:00:00 GMT
Granularita: il secondo. Se la risorsa cambia più volte al secondo (raro ma possibile), ETag e più affidabile.
Strong vs Weak ETag
Esistono due varianti:
- Strong:
ETag: "abc123"garantisce identità byte per byte. - Weak:
ETag: W/"abc123"indica equivalenza semantica, accetta piccole varianti (es. data compressione).
Vantaggi del 304
- Riduzione banda: nessun body trasferito.
- Latenza minima: solo header round-trip.
- Server load ridotto: confronto ETag e operazione cheap.
- UX migliore: pagine percepite come istantanee.
Configurazione Apache
FileETag MTime Size
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
</IfModule>
Configurazione Nginx
etag on;
location /static/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
ETag in API REST
Anche le API JSON beneficiano del 304:
GET /api/users/42 HTTP/1.1
If-None-Match: "user42-v17"
HTTP/1.1 304 Not Modified
ETag: "user42-v17"
Il client SPA mantiene il dato in stato e non rifa il fetch del body, accelerando re-render.
Header da NON includere nel 304
Per definizione, il 304 non ha body. Inoltre, NON deve includere header che modificherebbero la rappresentazione cacheata, come Content-Length (con valore reale del body), Content-Encoding, ecc. Va incluso solo cio che aggiorna i metadati del cache entry: ETag, Cache-Control, Expires.
Errori comuni
- ETag mismatch tra server: in cluster load-balanced, generare ETag deterministici da contenuto, non da metadati locali (es. inode).
- 304 con body: viola lo standard, alcuni client si confondono.
- Validators sbagliati: usare Last-Modified su file con stesso mtime ma contenuto diverso (es. touch).
Caching layers
Il 304 funziona attraverso più livelli: browser cache, service worker, CDN (Cloudflare, Fastly), reverse proxy (Varnish, Nginx). Ognuno puo validare con ETag verso il livello superiore, costruendo gerarchie efficienti.
Vary header e content negotiation
Quando la risposta dipende da header come Accept-Encoding, Accept-Language, User-Agent, includere Vary: nel 304 e nel 200 e fondamentale per cache CDN: indica di considerare quegli header come parte della cache key. Senza Vary, un'utente in italiano potrebbe vedere la pagina inglese cacheata e viceversa.
Conditional GET vs HEAD
Il 304 vale sia per GET condizionali che per HEAD. La differenza: HEAD non scarica body anche con 200, ma 304 conferma la freshness in entrambi i casi. Per pre-validazione, HEAD + If-Modified-Since e leggerissimo.
304 in SPA con SWR
Strategie come stale-while-revalidate (SWR) e service workers usano 304 intensivamente: il client mostra subito la versione cached, fa fetch in background e aggiorna solo se non e 304. UX percepita istantanea, dati sempre freschi.
Generazione ETag deterministica
In cluster load-balanced, generare ETag dal contenuto (es. SHA-256 del body) garantisce coerenza: due nodi diversi che servono la stessa risorsa emettono lo stesso ETag. Generare invece da metadata locali (inode, timestamp) puo creare cache miss spurie.
Service Worker e Cache API
Le moderne PWA possono cacheare 200 e poi validare con 304: fetch(req, { cache: 'no-cache' }) invia conditional GET. Se 304, mantiene cache; se 200, aggiorna. Ottimizzazione potente per offline-first apps.
Service Workers cache validation
Service Workers possono implementare strategie sofisticate di caching. Pattern stale-while-revalidate: ritorna dalla cache subito (rapido), in background fa fetch, se ottiene 304 mantiene cache, se 200 aggiorna. Pattern cache-first con fallback: prova cache, se miss fa fetch normale. Combinazioni di queste con If-None-Match danno esperienze offline-first robuste.
CDN edge validation
I CDN (Cloudflare, Fastly) implementano edge validation: edge node mantiene risorsa con ETag, periodicamente valida verso origin con If-None-Match. Se 304, mantiene; se 200, aggiorna. Riduce drasticamente carico origin senza servire content stantio.
Bandwidth saving real
Su asset statici (JS bundle, CSS), 304 riduce trasferimento da MB a poche centinaia di byte (solo header). Su pagine HTML dinamiche, dipende da quanto cambiano. Misurare con New Relic, Datadog il rapporto 304/200 per asset type.
ETag generation strategies
Strong ETag: hash crittografico del body (SHA-256). Weak ETag: hash di metadati più leggero. Per asset versionati con hash nel filename (es. app.abc123.js), ETag puo essere uguale al hash, semplicissimo.
Hai bisogno di aiuto?
Se il tuo sito mostra errori HTTP, il team di G Tech Group puo aiutarti. Contattaci tramite il modulo di contatto.