--- title: HTTP caching slug: Web/HTTP/Caching translation_of: Web/HTTP/Caching ---
Le prestazioni di siti web e applicazioni possono essere migliorate drasticamente riutilizzando le risorse già ottenute. Le web caches riducono la latenza e il traffico di rete, diminuendo il tempo necessario per rappresentare una risorsa. Attraverso l'uso dell'HTTP caching, i siti web diventano più responsivi.
Il caching è una tecnica che immagazzina una copia di una risorsa data e la restituisce quando richiesta. Quando una web cache ha una risorsa richiesta in memoria, intercetta la richiesta e ritorna la sua copia invece di riscaricarla dal server originale. Così si raggiungono diversi risultati: alleggerisce il carico del server che non deve più servire tutti i client da solo, e migliora le prestazioni stando più vicina al client, ad esempio, ci mette meno tempo a restituire le risorse. Per un sito web, è una componente fondamentale nell’ottenere prestazioni elevate. D’altra parte, deve essere configurato correttamente in quanto non tutte le risorse rimangono identiche per sempre. È importante mettere in cache una risorsa solo finché non cambia.
Ci sono diversi tipi di cache: queste possono essere raggruppate in due principali categorie: private o condivise. Una cache condivisa è una cache che immagazzina risposte per essere utilizzate da più utenti. Una cache privata è una cache dedicata ad un singolo utente. Questa pagina tratterà per la maggior parte delle browser cache e di quelle del proxy, ma ci sono anche gateway cache, CDN, reverse proxy cache e load balancer che sono impiegati nei server web per maggiore affidabilità, prestazioni e scaling di siti web e applicazioni web.
Una cache privata è dedicata ad un singolo utente. Potresti aver già visto “caching” nelle impostazioni del tuo browser. Una browser cache conserva tutti i documenti scaricati via http dall’utente. Questa cache è usata per rendere disponibili i documenti per la navigazione avanti o indietro, salvare, vedere come risorsa, ecc. senza inviare un'altra richiesta al server. Similmente migliora la ricerca offline di contenuti in cache.
Una cache condivisa è una cache che immagazzina risposte per essere utilizzate da più di un utente. Ad esempio, un ISP o la tua compagnia potrebbero aver impostato un web proxy come parte della sua infrastruttura network locale per servire molti utenti così che risorse popolari vengono riutilizzate più volte, riducendo il traffico di rete e la latenza.
L'HTTP caching non è obbligatorio, ma è normalmente utile. Le HTTP caches normalmente sono limitate alle risposte a {{HTTPMethod("GET")}} e potrebbero rifiutare altri metodi. La chiave primaria della cache consiste nel metodo richiesto e nell'URI desiderato (spesso viene usato solo l'URI, in quanto solo le richieste GET
vengono salvate nella cache).
Informazioni che spesso vengono salvate nella cache:
I dati inseriti possono essere composti da più risposte differenziate da una chiave secondaria se la richiesta è oggetto di scambio di contenuti. Per ulterior informazioni riguardo all'header {{HTTPHeader("Vary")}} leggi below.
Cache-Control
L'header generico {{HTTPHeader("Cache-Control")}} HTTP/1.1 viene usato per specificare i meccanismi del caching per richieste e risposte. Questo header può essere usato per definire le caching policies attraverso le direttive proposte.
La cache non dovrebbe salvare né le richieste né le risposte. Ogni richiesta viene mandata al server, dovendo quindi riscaricare ogni volta la risposta.
Cache-Control: no-store
La cache invia chiede una validazione da parte del server prima di fornire la sua copia.
Cache-Control: no-cache
La direttiva "public" indica che la risposta può essere salvata da qualsiasi cache. Questo può essere utile per salvare pagine con codici di risposta HTTP che normalmente non si potrebbero salvare.
Dall'altro lato, "private" indica che la risposta è legata ad un solo utente, quindi non sarà salvata in una cache condivisa. In questo caso la risposta potrebbe essere salvata da una cache privata del browser.
Cache-Control: private Cache-Control: public
La direttiva più importante è max-age=<secondi>
, che indica il tempo massimo (in secondi) in cui la risorsa è considerata fresca ("fresh"). Questa direttiva è relativa al tempo indicato dalla richiesta e sovrascrive l'header {{HTTPHeader("Expires")}} (se impostato). I file che non mutano (come ad esempio immagini, fogli CSS e script JavaScript) sono buoni candidati per essere salvati nella cache
Per ulteriori dettagli visita la sezione Freshness.
Cache-Control: max-age=31536000
Quando viene usata la direttiva "must-revalidate
" la cache deve verificare lo stato della risorsa prima di usarla, evitando le risorse scadute. Per ulteriori dettagli visita la sezione Validation.
Cache-Control: must-revalidate
Pragma
{{HTTPHeader("Pragma")}} è un header HTTP/1.0. Pragma: no-cache
corrisponde a Cache-Control: no-cache
, forzando quindi le cache a validare le risorse prima di utilizzarle. Pragma
non è incluso nelle risposte HTTP, quindi non può sostituire completamente l'header Cache-Control
presente in HTTP/1.1.
Si dovrebbe utilizzare l'header Pragma
solo per retrocompatibilità con le cache in HTTP/1.0, dove l'header Cache-Control
di HTTP/1.1 non è presente.
Una volta che una risorsa è memorizzata in cache, potrebbe teoricamente essere servita dalla cache per sempre. Le cache hanno una memoria finita quindi gli oggetti sono periodicamente rimossi dalla memoria. Questo processo si chiama sfratto della cache (cache eviction). D’altra parte, alcune risorse possono essere cambiate sul server quindi la cache andrebbe aggiornata. Dato che l’HTTP è un protocollo client-server, i server non possono contattare le cache e i client quando una risorsa cambia; devono comunicare un tempo di scadenza per la risorsa. Prima di questa scadenza, la risorsa è fresca; dopo la scadenza, la risorsa è datata. Gli algoritmi di sfratto spesso prediligono risorse fresche a quelle datate. Da notare che una risorsa datata non è sfrattata o ignorata; quando la cache riceve una richiesta per una risorsa datata, la inoltra con un If-None-Match per verificare se è di fatto ancora fresca. In questo caso il server ritorna un 304 (Non Modificata) header senza inviare il body della risorsa richiesta, risparmiando banda.
Qui è un esempio di questo processo con una proxy cache condivisa:
La durata della freschezza è calcolata secondo diversi header. Se l'header "Cache-Control: max-age=N
" è presente la durata sarà pari ad N, altrimenti (come spesso accade) si controlla se è presente l'header {{HTTPHeader("Expires")}}. Se esiste, la durata equivale alla differenza tra il valore dell'header {{HTTPHeader("Date")}} e il valore dell'header {{HTTPHeader("Expires")}}.
Se un server centrale non specifica esplicitamente la durata della freschezza (usando ad esempio gli header {{HTTPHeader("Cache-Control")}} o {{HTTPHeader("Expires")}}) potrebbe essere utilizzato un approccio euristico.
In questo caso si cerca l'header {{HTTPHeader("Last-Modified")}}. Se presente, la freschezza è uguale alla differenza tra il valore di ques'ultimo e il valore di Date
divisa per 10:
dataDiScadenza = orarioDellaRisposta + durataDellaFreschezza - tempoDiVitaCorrente
dove tempoDiRisposta
è l'ora in cui la risposta è stata ricevuta dal browser. Per maggiori informazioni: RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): 4.2.2. Calculating Heuristic Freshness.
Più si usa una risorsa in cache, più reattive saranno le risposte e le performance di un sito web. Per ottimizzarle, la norma è impostare i tempi di scadenza più in là possibile nel futuro. Questo è possibile con risorse che sono regolarmente aggiornate, o spesso, ma è problematico per risorse che vengono aggiornate raramente. Sono le risorse che beneficerebbero di più dalle cache, eppure questo le rende difficili da aggiornare. È tipico delle risorse tecniche incluse e linkate da ogni pagina web: I file Javascript e CSS cambiano di rado, ma quando succede vuoi che vengano aggiornati rapidamente.
I web developer hanno inventato una tecnica che Steve Souders chiamò revving. File sporadicamente aggiornati sono nominati in un modo specifico: nel loro URL, solitamente nel nome del file, un numero di revisione (o versione) viene aggiunto. In questo modo ogni nuova revisione di questa risorsa viene considerata come una risorsa che non cambia e può avere un tempo di scadenza molto avanti nel futuro, di solito un anno o più. Per avere le nuove versioni, tutti i link che fanno capo a loro vanno cambiati, questa è la limitazione di questo metodo: complessità aggiuntive vengono solitamente risolti dalle tool chain usate dai web developer. Quando la risorsa che cambia di rado viene modificata, questa induce un cambiamento aggiuntivo a risorse spesso variabili. Quando vengono lette, le nuove versioni della altre vengono anch’esse lette.
Questa tecnica ha un vantaggio aggiuntivo: aggiornare due risorse in cache nello stesso momento preverrà situazioni in cui la risorsa vecchia viene usata in combinazione con quella nuova dell’altra. Questo è molto importante quando i siti web hanno fogli CSS o script JS che hanno dipendenze reciproche, ad esempio che dipendono l’uno sull’altro perché si riferiscono agli stessi elementi HTML.
La versione di revisione aggiunta a una revved resource non ha bisogno di essere una classica stringa di revisione come 1.1.3, o un numero che aumenta monotonamente. Può essere qualsiasi cosa che impedisca le collisioni, come un hash o una data.
Quando una risorsa presente nella cache scade può essere validata o può essere richiesta nuovamente al server. La validazione può avvenire solo se il server ha fornito un validatore forte (strong validator) o un validatore debole (weak validator).
La rivalidazione comincia quando l'utente ricarica la pagina, oppure quando la risposta contenuta nella cache inculde l'header "Cache-Control: must-revalidate
". Un altro fattore è costituito dalle impostazioni nel pannello Avanzate->Cache
, dove è possibile forzare la validazione ogni volta che un documento viene caricato.
L'header {{HTTPHeader("ETag")}}, contenuto in una risposta, è un valore opaco per lo user agent (opaque-to-the-useragent) che può essere usato come un validatore forte. Questo significa che uno user-agent HTTP, ad esempio un browser, non sa cosa cosa questa stringa rappresenti e non può predirne il valore. Se l'header ETag
fosse parte di una risposta contenente una risorsa, il client può inserire {{HTTPHeader("If-None-Match")}} nell'header delle richieste future, così da validare le risorse salvate nella cache.
L'header {{HTTPHeader("Last-Modified")}}, contenuto in una risposta, può essere usato come un validatore debole. È considerato debole per via della sua risoluzione (un secondo). Se in una risposta è presente l'header Last-Modified
il client può inserire {{HTTPHeader("If-Modified-Since")}} nell'header della richiesta per validare il documento salvato nella cache.
Quando viene fatta una richiesta di validazione il server può ignorarla e rispondere con {{HTTPStatus(200)}} OK
, oppure può ritornare {{HTTPStatus(304)}} Not Modified
(senza corpo) per permettere al browser di usare il contenuto della cache. In quest'ultimo caso ci possono essere anche altri header che aggiornano la data di scadenza del documento salvato nella cache.
L'header delle risposte HTTP {{HTTPHeader("Vary")}} indica gli header con cui usare una risposta salvata nella cache.
Quando una cache riceve una richiesta contenente l'header Vary
non deve usare una risposta salvata nella cache, a meno che tutti gli header contenuti nel campo Vary
corrispondano agli header contenuti nella cache.
Questa proprietà viene principalmente usata per salvare nella cache una risorsa non compressa o compressa in vari formati, per inviarla poi agli user agent a seconda delle codifiche che supportano. Per esempio, un server può impostare Vary: Accept-Encoding
per assicurarsi che la risorsa sia salvata nella cache secondo le codifiche richieste, come Accept-Encoding: gzip,deflate,sdch
.
Vary: Accept-Encoding
Vary
cautamente—può ridurre drasticamente i vantaggi del caching! Un caching server dovrebbe usare la normalizzazione per rimuovere duplicati e richieste non necessarie. Questo si verifica particolarmente quando si usa Vary
con header che possono accettare diversi valori.L'header Vary
può tornare utile per fornire contenuti diversi a utenti mobili o desktop, o per permettere ai motori di ricerca di ottenere la versione mobile di una pagina (specificando opzionalmente che non c'è Cloaking). Questo viene attuato con l'header Vary: User-Agent
, dato che il valore dell'header {{HTTPHeader("User-Agent")}} è diverso tra desktop e mobile.
Vary: User-Agent
Come anticipato sopra, i caching server utilizzerano le risposte salvate nella cache solo con le richieste i cui header (e valori annessi) corrispondono esattamente alle risposte salvate. Questo significa che per ogni piccola differenza verrà fatta una nuova richiesta al server centrale, che verrà poi salvata nella cache.
Per esempio, tutte le richieste con i seguenti header verranno richieste al server, per poi essere salvate nella cache: Accept-Encoding: gzip,deflate,sdch
, Accept-Encoding: gzip,deflate
, Accept-Encoding: gzip
. Probabilmente, però, il server centrale risponderà sempre con la stessa risorsa (un file gzip)!
Per evitare duplicati e richieste non necessarie, i caching server dovrebbero usare la normalizzazione per pre-processare le richieste e per salvare solo i file necessari nella cache. Ad esempio, nel caso di Accept-Encoding
si possono controllare gzip
e gli altri tipi di compressione prima di procedere. In "pseudo codice" si può codificare come:
// Normalizza Accept-Encoding
if (req.http.Accept-Encoding) {
if (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
}
// elsif other encoding types to check
else {
unset req.http.Accept-Encoding;
}
}
User-Agent
ha ancora più varianti di Accept-Encoding
. Quindi s Vary: User-Agent
viene utilizzato per salvare nella cache le varianti dei file per mobile/desktop si potrebbe controllare se "mobile"
e "desktop"
sono presenti nell'header User-Agent
.