Indice dei contenuti dell'articolo:
Esistono molte intestazioni HTTP diverse che possono essere utilizzate dal tuo sito web. In questo momento, ci concentreremo su un sottoinsieme specifico di questi: le intestazioni della cache. Ti mostreremo i dettagli quando si tratta di intestazioni della cache, quindi in futuro saprai come usarle!
Nel contesto di siti Web e app, la memorizzazione nella cache è definita come la memorizzazione del contenuto in una memoria temporanea, come quella sul browser o sul dispositivo dell’utente o su un server intermedio, per ridurre il tempo necessario per accedere a quel file.
Secondo HTTP Archive, tra i primi 300.000 siti, il browser dell’utente può memorizzare nella cache quasi la metà di tutto il contenuto scaricato.
Riduce il tempo necessario all’utente per visualizzare le immagini oi file Javascript o CSS. Questo perché l’utente ora accede al file dal suo sistema invece di essere scaricato dalla rete. Allo stesso tempo, la memorizzazione nella cache riduce anche il numero di richieste e il trasferimento di dati dai tuoi server. Indubbiamente questo è un enorme risparmio per le visualizzazioni e le visite ripetute di pagina.
Come funziona la memorizzazione nella cache?
Supponiamo di aprire una pagina web https://www.example.com e che il server restituisca il seguente codice HTML:
...
<link type="text/css" href="https://www.example.com/app.css" rel="stylesheet">
...
<!-- Rest of the HTML -->
Quando il browser analizza questo codice HTML, identifica che una risorsa CSS deve essere caricata da https://www.example.com/app.css .
Il browser invia una richiesta al server per questo file, il server restituisce il file e dice anche al browser di memorizzarlo nella cache per 30 giorni. Più avanti in questa guida, tratteremo come il server invia queste istruzioni al browser.
Ora, supponiamo che tu apra un’altra pagina sullo stesso sito Web dopo alcune ore. Il browser analizza nuovamente l’HTML e trova lo stesso file CSS anche in questa pagina: https://www.example.com/app.css . Poiché il browser ha questa particolare risorsa disponibile nella sua cache locale, non andrà nemmeno al server. La richiesta di rete non viene mai effettuata, si accede al file dalla cache locale e gli stili vengono applicati molto rapidamente.
Come si realizza?
Esiste una gamma di intestazioni di cache e relative direttive che forniscono istruzioni esplicite a qualsiasi server, CDN e browser dell’utente finale su come gestire il contenuto in termini di cache. La combinazione di più funzionalità può darti i risultati desiderati o potrebbero causare il mancato funzionamento della cache perché vengono utilizzate in modo errato. Ti forniremo una rapida panoramica delle intestazioni della cache HTTP più comuni , delle loro direttive e di come utilizzarle.
Cache-Control: direttive
Esistono più direttive che possono essere utilizzate per controllare la funzionalità delle intestazioni della cache. Non devi usarli tutti, quindi scegli quelli che ti servono e lascia fuori gli altri. Queste sono le direttive più importanti:
max-age
Nella maggior parte degli usi delle intestazioni di controllo della cache vedrai questa direttiva in uso. Indica la quantità di tempo massima in secondi in cui le risposte recuperate possono essere riutilizzate dal momento in cui viene effettuata una richiesta. Ad esempio: max-age=300
indica che una risorsa può essere riutilizzata per i successivi 300 secondi. Questa risorsa può essere memorizzata nella cache dal browser o da qualsiasi cache a valle del server per questo periodo di tempo.
s-maxage
Il s-
prefisso “ ” sta per condiviso come nella cache condivisa. Questa direttiva è esplicitamente per CDN tra le altre cache intermedie. Questa direttiva sovrascrive la max-age
direttiva e fa scadere il campo di intestazione quando presente. È importante ricordare che questa direttiva non influirà sui browser dei visitatori. Quindi puoi utilizzare valori diversi per mag-age
e s-maxage
specificare tempi di cache diversi sia per i visitatori che per i CDN.
Può essere utile, ad esempio qualora utilizziate sistemi di cache come Varnish e vogliate istruire il server cache a settare un determinato tempo di cache alcune pagine.
no-cache
La no-cache
direttiva mostra che le risposte restituite non possono essere utilizzate per richieste successive allo stesso URL prima di verificare se le risposte del server sono state modificate. Con un ETag appropriato (noto anche come token di convalida) presente, di conseguenza, si verifica no-cache
un roundtrip nel tentativo di convalidare le risposte memorizzate nella cache. Le cache possono tuttavia eliminare i download se le risorse non sono cambiate. Ciò significa che i browser Web potrebbero memorizzare nella cache gli asset ma devono controllare ogni richiesta se gli asset sono cambiati (il server restituirà una risposta HTTP 304 se non è cambiato nulla).
no-store
Diversamente da no-cache
, la no-store
direttiva è più semplice. Questo perché impedisce ai browser e a tutte le cache intermedie di archiviare qualsiasi versione delle risposte restituite, ad esempio risposte contenenti informazioni private/personali o dati bancari. Ogni volta che gli utenti richiedono questo asset, le richieste vengono inviate al server. Le risorse vengono scaricate ogni volta.
public
Se una risposta è contrassegnata come pubblica, può essere memorizzata nella cache anche nei casi in cui è associata a un’autenticazione HTTP o il codice di stato della risposta HTTP non è normalmente memorizzabile nella cache. Poiché le informazioni esplicite sulla memorizzazione nella cache, ad esempio tramite la max-age
direttiva, mostrano che una risposta è comunque memorizzabile nella cache, l’utilizzo di questa direttiva di solito non è necessario.
Nella maggior parte dei casi, una risposta contrassegnata come public non è necessaria, poiché le informazioni di memorizzazione nella cache esplicite (ad es. max-age
) mostrano che una risposta è comunque memorizzabile nella cache.
private
Una risposta contrassegnata come privata può essere memorizzata nella cache dal browser. Tuttavia, queste risposte sono generalmente destinate a utenti singoli, quindi non sono memorizzabili nella cache da cache intermedie (ad es. pagine HTML con informazioni utente private possono essere memorizzate nella cache dal browser di un utente ma non da una CDN).
expires
Tempo fa questa intestazione veniva utilizzata per sfruttare i meccanismi di memorizzazione nella cache. Questa intestazione contiene semplicemente un contrassegno di data e ora. È ancora utile per i vecchi programmi utente, ma è importante notare che le intestazioni Cache-Control max-age
hanno s-maxage
ancora la precedenza sulla maggior parte dei sistemi moderni.
last-modified
Questa intestazione è uno dei validatori più comuni per la cache. Indica quando una risorsa richiesta è stata modificata l’ultima volta. Anche se è uno dei validatori più comuni, le sue origini risalgono all’era HTTP/1.0, rendendolo visto da alcuni come un validatore legacy.
Etag
Un metodo di convalida più recente è l’utilizzo di ETag. Questo è diventato lo standard da HTTP/1.1. Questo viene convalidato tramite un campo di intestazione ETag. Di solito si basa su un hash del contenuto richiesto, ma non deve essere così. Tuttavia, il client che lo richiede non deve avere alcuna conoscenza di come viene generato. Se un client ha un oggetto nella sua cache che è scaduto, può utilizzare l’ETag per inviare una richiesta HTTP al server. Il server verificherà quindi questo token rispetto alle risorse memorizzate nella cache. Se l’asset non è stato modificato, il server può restituire una risposta 304 non modificata al client. Ciò rigenererà la durata della risorsa memorizzata nella cache, invece di riscaricare la risorsa.
Etag può essere un header di convalida sostitutivo o complementare a last-modified. Può essere particolarmente utile implementarlo quando si ha a che fare con intestazioni last-modified errate o si ha la necessità di disabilitarle rimuovendo l’header.
Vediamo dei casi pratici
Qualsiasi tipo di memorizzazione nella cache normalmente funzionerebbe attraverso l’aggiornamento e la convalida. Spieghiamo cosa significa. Le nuove richieste in genere ti daranno una nuova copia del contenuto servito istantaneamente dalla cache. Tuttavia, una rappresentazione convalidata raramente invierà di nuovo l’intera copia se non è cambiata dall’ultima volta che l’hai richiesta. Nei casi in cui non è presente alcun validatore (ad esempio un ETag o un’intestazione Last-Modified) combinato con una mancanza di informazioni sulla freschezza, di solito sarà considerato non memorizzabile nella cache.
Ottenere la corretta memorizzazione nella cache offre enormi vantaggi in termini di prestazioni, consente di risparmiare larghezza di banda e riduce i costi del server, ma molti siti utilizzano metà della memorizzazione nella cache, creando condizioni di competizione con conseguente perdita di sincronizzazione delle risorse interdipendenti.
La stragrande maggioranza della memorizzazione nella cache delle migliori pratiche rientra in uno dei due modelli seguenti:
Schema 1: contenuto immutabile + max-age
Cache-Control: max-age=31536000
- Il contenuto di questo URL non cambia mai, quindi…
- Il browser/CDN può memorizzare nella cache questa risorsa per un anno senza problemi
- Il contenuto memorizzato nella cache di meno di
max-age
secondi può essere utilizzato senza consultare il server
In questo modello, non modifichi mai il contenuto in un determinato URL, cambi l’URL:
<script src="/script-f93bca2c.js"></script>
<link rel="stylesheet" href="/styles-a837cb1e.css" />
<img src="/cats-0e9a2ef4.jpg" alt="…" />
Ogni URL contiene qualcosa che cambia insieme al suo contenuto. Potrebbe essere un numero di versione, la data di modifica o un hash del contenuto, che è quello che faccio su questo blog.
Tuttavia, questo modello non funziona per cose come articoli e post di blog. I loro URL non possono essere versionati e il loro contenuto deve poter cambiare. Seriamente, dati gli errori di ortografia e grammatica di base che commetto, devo essere in grado di aggiornare i contenuti in modo rapido e frequente.
Schema 2: contenuto modificabile, sempre riconvalidato dal server
Cache-Control: no-cache
- Il contenuto di questo URL potrebbe cambiare, quindi…
- Qualsiasi versione memorizzata nella cache locale non è attendibile senza l’autorizzazione del server
Nota: no-cache
non significa “non memorizzare nella cache”, significa che deve controllare (o “riconvalidare” come lo chiama) con il server prima di utilizzare la risorsa memorizzata nella cache. no-store
dice al browser di non memorizzarlo affatto nella cache. Inoltre must-revalidate
non significa “deve rivalidare”, significa che la risorsa locale può essere utilizzata se è più giovane di quella fornita max-age
, altrimenti deve essere riconvalidata. Sì. Lo so.
In questo modello puoi aggiungere un’intestazione ETag
(un ID versione a tua scelta) o una Last-Modified
data alla risposta. La prossima volta che il client recupera la risorsa, fa eco al valore per il contenuto che ha già tramite If-None-Match
e If-Modified-Since
rispettivamente, consentendo al server di dire “Usa solo ciò che hai già, è aggiornato” o come si scrive ” HTTP 304″.
Se l’invio ETag
/ Last-Modified
non è possibile, il server invia sempre l’intero contenuto.
Questo modello comporta sempre un recupero della rete, quindi non è buono come il modello 1 che può bypassare completamente la rete.
Non è raro essere scoraggiati dall’infrastruttura necessaria per il modello 1, ma allo stesso modo essere scoraggiati dalla richiesta di rete richiesta dal modello 2 e invece scegliere qualcosa nel mezzo: un max-age
contenuto piccolo e mutevole. Questo è un bel compromesso.
max-age su contenuti mutevoli è spesso la scelta sbagliata
…e sfortunatamente non è raro, ad esempio accade sulle pagine di Github.
Immaginare:
/article/
/styles.css
/script.js
…il tutto servito con:
Cache-Control: deve essere riconvalidato, max-age=600
- Il contenuto degli URL cambia
- Se il browser ha una versione memorizzata nella cache di meno di 10 minuti, usala senza consultare il server
- In caso contrario, effettuare un recupero di rete, utilizzando
If-Modified-Since
oIf-None-Match
se disponibile
Questo modello può sembrare funzionare durante i test, ma rompe le cose nel mondo reale ed è davvero difficile da rintracciare. Nell’esempio sopra, il server aveva effettivamente aggiornato HTML, CSS e JS, ma la pagina ha finito con il vecchio HTML e JS dalla cache e il CSS aggiornato dal server. La mancata corrispondenza della versione ha rotto le cose.
Spesso, quando apportiamo modifiche significative all’HTML, è probabile che modifichiamo anche il CSS per riflettere la nuova struttura e aggiorniamo il JS per soddisfare le modifiche allo stile e al contenuto. Queste risorse sono interdipendenti, ma le intestazioni di memorizzazione nella cache non possono esprimerlo. Gli utenti potrebbero ritrovarsi con la nuova versione di una/due delle risorse, ma la vecchia versione dell’altra/e.
max-age
è relativo al tempo di risposta, quindi se tutte le risorse di cui sopra sono richieste come parte della stessa navigazione verranno impostate per scadere più o meno alla stessa ora, ma c’è ancora la piccola possibilità di una gara lì. Se disponi di alcune pagine che non includono JS o includono CSS diversi, le date di scadenza potrebbero non essere sincronizzate. E peggio, il browser elimina continuamente le cose dalla cache e non sa che HTML, CSS e JS sono interdipendenti, quindi rilascerà felicemente uno ma non gli altri. Moltiplica tutto questo insieme e non è improbabile che tu possa ritrovarti con versioni non corrispondenti di queste risorse.
Per l’utente, ciò può causare layout e/o funzionalità interrotti. Da piccoli difetti a contenuti del tutto inutilizzabili.