HTTP 304 Not Modified: non rispedire ciò che il browser ha già

Con ETag, Last-Modified e richieste condizionali il server risponde 304 senza ritrasferire i file: come funziona, quando aiuta il TTFB e il crawling budget e gli errori da evitare.

Il codice 304 Not Modified con zero kilobyte di corpo, accanto a una richiesta condizionale con If-None-Match e alla risposta HTTP/2 304 con lo stesso ETag e Cache-Control max-age di un’ora

Quando si parla di velocità si pensa subito a cache delle pagine, CDN, compressione, immagini leggere e JavaScript ridotto. C’è però un meccanismo molto meno appariscente che lavora in silenzio su ogni visita di ritorno e su ogni passaggio dei motori di ricerca: il codice di stato HTTP 304 Not Modified. Non cambia l’aspetto della pagina e non aggiunge funzioni, ma evita di trasferire ciò che il browser o il crawler possiedono già. Configurato bene, riduce traffico e carico sul server, aiuta il TTFB e rende più efficiente la scansione del sito.

Che cos’è il 304 Not Modified

Il 304 è la risposta a una domanda precisa: “la risorsa è cambiata dall’ultima volta che l’ho scaricata?”. Se la risposta è no, il server non rispedisce il contenuto, ma solo le intestazioni con lo stato 304, e il client continua a usare la copia che ha in cache. Se invece la risorsa è cambiata, risponde con un normale 200 OK e il nuovo contenuto.

Non si tratta di una cache arbitraria, ma del risultato di una richiesta condizionale. Alla prima richiesta il server accompagna la risorsa con un identificatore di versione, l’intestazione ETag, e con la data dell’ultima modifica, Last-Modified. Alle richieste successive il client li rimanda indietro con If-None-Match e If-Modified-Since, e il server li confronta con lo stato attuale.

Scambio tra browser o crawler e server: alla prima richiesta di style.css il server risponde 200 OK con 150 KB, un ETag e la data di ultima modifica; alla richiesta successiva il client invia If-None-Match con lo stesso ETag e il server risponde 304 Not Modified senza corpo, così il client usa la copia in cache
Prima un 200 con l’identificatore di versione, poi un 304 senza corpo: il file non viaggia due volte.

Scadenza e validazione: due cose diverse

Per usare bene il 304 bisogna distinguere due meccanismi che spesso vengono confusi. La scadenza, governata da Cache-Control: max-age, stabilisce per quanto tempo il client può usare la copia senza chiedere nulla al server: in quel periodo non parte nessuna richiesta. La validazione entra in gioco dopo: quando la copia è scaduta, il client chiede conferma con una richiesta condizionale e riceve un 304 se nulla è cambiato.

Una risorsa nel tempo con max-age di un’ora e un ETag: al tempo zero viene scaricata con un 200, per un’ora le visite usano la copia locale senza richieste, a un’ora e a due ore la copia viene validata con un 304 senza corpo, a tre ore la risorsa è cambiata e arriva un nuovo 200
La scadenza evita le richieste, la validazione evita di ritrasferire il file quando la copia scade.

Una configurazione efficace combina i due: tempi di scadenza coerenti con la frequenza di aggiornamento e identificatori di versione affidabili per validare quando serve. Solo la scadenza, con tempi lunghi, rischia di mostrare contenuti superati; solo la validazione, senza scadenza, genera una richiesta per ogni risorsa a ogni pagina. Attenzione anche a un equivoco frequente: Cache-Control: no-cache non significa “non mettere in cache”, ma “valida sempre prima di usare la copia”. Chi vuole davvero impedire la memorizzazione deve usare no-store.

ETag o Last-Modified?

Last-Modified è semplice: una data, confrontata con quella che il client rimanda. Ha una precisione di un secondo e dipende dalla data del file, che può cambiare anche senza che cambi il contenuto, per esempio dopo un nuovo deploy. ETag identifica la versione vera e propria, spesso con un hash del contenuto, ed è più preciso.

Negli ambienti con più server l’ETag richiede però attenzione. Alcuni web server lo calcolano anche a partire da dati del filesystem, come l’inode, diversi da un nodo all’altro: lo stesso file ottiene ETag diversi a seconda del server che risponde, e le validazioni falliscono. In un cluster conviene generare l’ETag solo da dimensione e data di modifica, o a livello di applicazione, CDN o build, in modo coerente su tutti i nodi.

# Nginx: ETag e Last-Modified sono attivi per i file statici
etag on;
if_modified_since exact;

# Apache: ETag senza inode, coerente tra più server
FileETag MTime Size

Perché il 304 aiuta il TTFB

Una risposta 304 è minuscola: solo intestazioni, nessun corpo. Per il client significa poter usare subito la copia locale; per il server, meno byte da inviare, meno I/O e meno CPU. Ma è importante essere precisi: il 304 non abbassa il TTFB in automatico. Se per decidere che una pagina non è cambiata l’applicazione deve comunque avviare PHP, interrogare il database e caricare tutti i plugin, il tempo di risposta resta quasi lo stesso: si risparmia solo il trasferimento. Il vantaggio vero arriva quando la validazione avviene negli strati più leggeri dell’infrastruttura.

Costo lato server di una risposta 304 a seconda di dove avviene la validazione, esempio illustrativo: pochi millisecondi su CDN, reverse proxy come Varnish e web server come Nginx, circa 850 millisecondi se la decisione spetta all’applicazione dopo aver generato la pagina
Esempio illustrativo: lo stesso 304 costa pochi millisecondi in un reverse proxy e quasi un secondo se deve deciderlo il CMS.

Una CDN può validare direttamente sui propri nodi, un reverse proxy come Varnish può rispondere dalla memoria senza coinvolgere l’applicazione, e Nginx gestisce i file statici con ETag e Last-Modified in modo efficientissimo. Più la validazione è vicina al livello HTTP e lontana dal codice applicativo, più il 304 conviene. È lo stesso principio della cache di pagina, di cui abbiamo parlato in TTFB e cache di pagina.

304 e crawling budget

I motori di ricerca dedicano a ogni sito una quantità limitata di risorse per la scansione. Ogni inefficienza, come risposte lente o contenuti scaricati di nuovo senza motivo, può tradursi in meno pagine visitate e aggiornamenti indicizzati più tardi. Google ha confermato che i suoi crawler supportano le richieste condizionali con ETag e Last-Modified: quando una risorsa già nota non è cambiata, un 304 permette di verificarla senza riscaricarla, con meno lavoro sia per il crawler sia per il server.

Nel rapporto Statistiche di scansione di Search Console le risposte 304 compaiono tra i codici di stato, e permettono di capire quanto spesso Googlebot trova risorse invariate. Il 304 non migliora da solo il posizionamento e non aumenta per magia il budget di scansione, ma nei siti grandi, come cataloghi e-commerce o archivi editoriali, contribuisce a una scansione più ordinata e a un server meno sollecitato.

Risorse statiche: dove il 304 rende di più

CSS, JavaScript, immagini e font cambiano raramente ma vengono richiesti moltissime volte, da utenti e bot. Senza intestazioni corrette il browser rischia di scaricarli di nuovo a ogni visita con risposte 200 complete; con una buona configurazione li riusa dalla cache e, quando serve, li valida con un 304. Il guadagno si sente sulle visite di ritorno e nei picchi di traffico, quando migliaia di richieste identiche competono con quelle dinamiche.

Per i file con la versione nel nome, come app.8f3a21.css, si può fare ancora meglio: una scadenza lunghissima e la direttiva immutable. Finché il nome non cambia, il file non viene nemmeno validato; a ogni nuova versione cambia il nome e il browser lo scarica. È la strategia ideale, e il 304 resta lo strumento per tutto ciò che non può essere versionato così.

# File con la versione nel nome: mai validati finché il nome non cambia
Cache-Control: public, max-age=31536000, immutable

# File senza versione nel nome: scadenza breve, poi validazione con 304
Cache-Control: public, max-age=3600
ETag: "a1b2c3"

L’HTML dinamico: usarlo con criterio

Con le pagine HTML il discorso è più delicato. Una home con contenuti che cambiano spesso, banner, widget e parti personalizzate non è un buon candidato per il 304, almeno senza un livello di cache ben progettato: se l’applicazione deve generare tutta la pagina per capire se è cambiata, il 304 arriva troppo tardi per essere utile, e una validazione ingenua rischia di considerare invariati contenuti che variano per utente, carrello o area geografica. Funziona invece molto bene per pagine stabili servite da un reverse proxy: articoli, documentazione, landing page, schede prodotto che cambiano di rado.

Gli errori più comuni

  • Contare i 304 come segno di buona salute. Molti 304 su file che non cambiano mai indicano una scadenza troppo breve: meglio servirli direttamente dalla cache locale, senza alcuna richiesta.
  • ETag diversi tra i nodi. In un cluster, lo stesso file con identificatori diversi viene riscaricato di continuo.
  • Validazione nel posto sbagliato. Un 304 prodotto dal CMS dopo aver generato l’intera pagina risparmia solo banda, non tempo.
  • Intestazioni in conflitto. Plugin e livelli diversi che impostano direttive contraddittorie producono flussi di richieste inefficienti e difficili da capire.
  • Contenuti personalizzati validati come statici. Tutto ciò che dipende da sessione, carrello o area geografica va separato dal contenuto condivisibile.

Come verificarlo

Si parte dalle intestazioni: una prima richiesta per leggere ETag e Last-Modified, una seconda condizionale per verificare che la risposta sia davvero un 304.

# Leggere le intestazioni di cache
curl -sI https://www.iltuosito.it/css/style.css | grep -iE "etag|last-modified|cache-control"

# Richiesta condizionale con l’ETag appena letto
curl -sI -H 'If-None-Match: "a1b2c3"' https://www.iltuosito.it/css/style.css | head -1
HTTP/2 304

Conviene ripetere il test più volte, per verificare che nodi diversi restituiscano lo stesso ETag, e controllare nel pannello Network dei DevTools il comportamento al ricaricamento della pagina. I log del web server mostrano quante richieste terminano con 304, su quali risorse e con quale tempo di risposta: se un 304 costa quasi quanto un 200, la validazione avviene troppo in alto nello stack. Per la parte SEO, gli stessi log e le statistiche di scansione di Search Console mostrano quanto Googlebot usa le richieste condizionali.

In sintesi

Il 304 Not Modified permette di non rispedire ciò che il client possiede già: meno byte, meno lavoro per il server, visite di ritorno più rapide e una scansione più efficiente per i motori di ricerca. Funziona al meglio insieme a una buona politica di scadenza, con ETag coerenti o Last-Modified affidabili, e con la validazione affidata agli strati più leggeri dell’infrastruttura: CDN, reverse proxy e web server, non l’applicazione.

Non è un trucco né una scorciatoia, e non sostituisce un’architettura di cache ben progettata. È piuttosto l’applicazione di un principio semplice che attraversa tutte le Web Performance: il lavoro più veloce è quello che non si fa. Non rispedire un file, non generare di nuovo una risposta, non occupare banda e CPU per nulla: su migliaia di richieste al giorno, fa la differenza.

IL PROSSIMO PASSO

Partiamo
dal tuo sito.

Raccontaci il progetto, i problemi che riscontri e i tuoi obiettivi. Definiremo insieme un intervento su misura.

Richiedi un’analisi

Ti porta al modulo della pagina Contatti.

MANAGED SERVER S.R.L.info@corewebvitals.it +39 02 5656 9681

Lunedì – venerdì · 09:30 – 19:30

Preferisci un modulo online?
Contattaci su managedserver.it ↗