Evitare richieste di rete non necessarie con la cache HTTP

Il recupero delle risorse sulla rete è lento e costoso:

  • Le risposte di grandi dimensioni richiedono molti round trip tra il browser e il server.
  • La pagina non verrà caricata finché tutte le risorse critiche non saranno state scaricate completamente.
  • Se un utente del tuo sito ha un piano dati mobili limitato, ogni richiesta di rete non necessaria è uno spreco di denaro.

Come si possono evitare richieste di rete inutili? La cache HTTP del browser è la prima linea di difesa. Non è necessariamente l'approccio più potente o flessibile e hai un controllo limitato sulla durata delle risposte memorizzate nella cache, ma è efficace, è supportato in tutti i browser e non richiede molto lavoro.

Questa guida illustra le nozioni di base per un'implementazione efficace della memorizzazione nella cache HTTP.

Compatibilità del browser

Cache HTTP è il nome generale di una raccolta di API delle piattaforme web supportate in tutti i browser:

Cache-Control

Supporto dei browser

  • True
  • 12
  • True
  • True

Origine

ETag

Supporto dei browser

  • True
  • 12
  • True
  • True

Origine

Last-Modified

Supporto dei browser

  • True
  • 12
  • True
  • True

Origine

Funzionamento della cache HTTP

Tutte le richieste HTTP effettuate dal browser vengono instradate prima alla cache del browser per verificare se esiste una risposta memorizzata nella cache che possa essere utilizzata per soddisfare la richiesta. Se c'è una corrispondenza, la risposta viene letta dalla cache, il che elimina sia la latenza di rete sia i costi dei dati del trasferimento.

Il comportamento della cache HTTP è controllato da una combinazione di intestazioni della richiesta e intestazioni della risposta. In uno scenario ideale, hai il controllo sia sul codice della tua app web, che determina le intestazioni delle richieste, sia sulla configurazione del tuo server web, che determina le intestazioni delle risposte.

Per una panoramica concettuale più approfondita, consulta l'articolo Memorizzazione nella cache HTTP di MDN.

Intestazioni delle richieste: mantieni i valori predefiniti (di solito)

Esiste una serie di intestazioni importanti che dovrebbero essere incluse nelle richieste in uscita della tua applicazione web, ma quasi sempre il browser si occupa di impostarle per tuo conto quando effettua le richieste. Le intestazioni delle richieste che influiscono sulla verifica dell'aggiornamento, come If-None-Match e If-Modified-Since, vengono visualizzate in base alla comprensione da parte del browser dei valori correnti nella cache HTTP.

Questa è una buona notizia: significa che puoi continuare a includere tag come <img src="my-image.png"> nel tuo codice HTML e il browser si occupa automaticamente della memorizzazione nella cache HTTP senza alcuno sforzo.

Intestazioni della risposta: configura il server web

La parte più importante della configurazione della memorizzazione nella cache HTTP è costituita dalle intestazioni aggiunte dal server web a ogni risposta in uscita. Tutte le intestazioni riportate di seguito contribuiscono a un efficace comportamento della memorizzazione nella cache:

Cache-Control
Il server può restituire un'istruzione Cache-Control per specificare come e per quanto tempo il browser e altre cache intermedie devono memorizzare nella cache la risposta individuale.
ETag.
Quando il browser trova una risposta memorizzata nella cache, può inviare al server un piccolo token (di solito un hash dei contenuti del file) per verificare se il file è stato modificato. Se il server restituisce lo stesso token, il file è lo stesso e non è necessario scaricarlo di nuovo.
Last-Modified
Questa intestazione ha lo stesso scopo di ETag, ma utilizza una strategia basata sul tempo per determinare se una risorsa è cambiata, al contrario della strategia basata sui contenuti di ETag.

Alcuni server web dispongono di supporto integrato per l'impostazione di queste intestazioni per impostazione predefinita. Altre ignorano completamente le intestazioni, a meno che non le configuri esplicitamente. I dettagli specifici della modalità di configurazione delle intestazioni variano notevolmente a seconda del server web utilizzato. Per informazioni più dettagliate, consulta la documentazione del server.

Per evitare di eseguire ricerche, ecco le istruzioni per configurare alcuni dei server web più diffusi:

Se viene esclusa l'intestazione della risposta Cache-Control, la memorizzazione nella cache HTTP non viene disattivata. Invece, i browser prevedono efficacemente il tipo di comportamento della memorizzazione nella cache più adatto a un determinato tipo di contenuti. Probabilmente vuoi avere un controllo maggiore di quello offerto, quindi dovrai dedicare tutto il tempo necessario alla configurazione delle intestazioni delle risposte.

Quali valori dell'intestazione della risposta devi utilizzare?

Sono due gli scenari importanti da considerare durante la configurazione delle intestazioni di risposta del server web.

Memorizzazione nella cache di lunga durata per gli URL con versione

In che modo gli URL con versioni possono contribuire alla strategia di memorizzazione nella cache
Gli URL con più versioni sono una buona pratica perché rendono più facile invalidare le risposte memorizzate nella cache.

Supponiamo che il tuo server indichi ai browser di memorizzare nella cache un file CSS per 1 anno (Cache-Control: max-age=31536000) e che il tuo designer abbia appena apportato un aggiornamento di emergenza che devi implementare immediatamente. Come comunichi ai browser di aggiornare la copia cache "inattiva" del file? Non puoi, almeno non senza modificare l'URL della risorsa.

Dopo che il browser ha memorizzato la risposta nella cache, la versione memorizzata nella cache viene utilizzata fino a quando non è più aggiornata, come stabilito da max-age o expires, o fino a quando non viene eliminata dalla cache per altri motivi, ad esempio quando l'utente svuota la cache del browser. Di conseguenza, utenti diversi potrebbero finire a caricare versioni diverse del file quando viene creata la pagina: gli utenti che hanno appena recuperato la risorsa utilizzano la nuova versione, mentre gli utenti che hanno memorizzato nella cache una copia precedente (ma ancora valida) utilizzano una versione precedente.

Per ottenere sia la memorizzazione nella cache lato client sia aggiornamenti rapidi, puoi modificare l'URL della risorsa e forzare l'utente a scaricare la nuova risposta ogni volta che cambia il contenuto. In genere, puoi eseguire questa operazione incorporando un'impronta digitale del file o un numero di versione nel nome del file, ad esempio style.x234dff.css.

Quando rispondi alle richieste di URL che contengono informazioni sul "fingerprint" o sul controllo delle versioni e i cui contenuti non devono mai essere modificati, aggiungi Cache-Control: max-age=31536000 alle tue risposte.

L'impostazione di questo valore indica al browser che, quando deve caricare lo stesso URL in qualsiasi momento nel corso dell'anno successivo (31.536.000 secondi, il valore massimo supportato), può utilizzare immediatamente il valore nella cache HTTP senza dover effettuare alcuna richiesta di rete al server web. Ottimo lavoro: hai subito acquisito l'affidabilità e la velocità che derivano dall'aver eliminato la rete.

Strumenti come il webpack possono automatizzare il processo di assegnazione delle fingerprint di hash agli URL degli asset.

Riconvalida del server per gli URL senza versione

Purtroppo, non tutti gli URL caricati hanno il controllo delle versioni. Forse non puoi includere un passaggio di build prima di eseguire il deployment della tua applicazione web, quindi non puoi aggiungere hash agli URL degli asset. Ogni applicazione web ha bisogno di file HTML, che quasi mai includono le informazioni sul controllo delle versioni, perché nessuno si preoccuperà di utilizzare la tua app web se ha bisogno di ricordare che l'URL da visitare è https://example.com/index.34def12.html. Cosa puoi fare per questi URL?

La memorizzazione nella cache HTTP da sola non è abbastanza potente da evitare del tutto la rete. Ma non preoccuparti, presto scoprirai i lavoratori dei servizi, che forniscono ulteriore assistenza. Esistono però alcuni passaggi che puoi adottare per assicurarti che le richieste di rete siano il più rapide ed efficienti possibile.

I seguenti valori Cache-Control possono aiutarti a ottimizzare dove e come gli URL senza versione vengono memorizzati nella cache:

  • no-cache comunica al browser che deve riconvalidarlo ogni volta prima di utilizzare una versione dell'URL memorizzata nella cache.
  • no-store indica al browser e ad altre cache intermedie (come le CDN) di non archiviare mai alcuna versione del file.
  • private: i browser possono memorizzare nella cache il file, ma le cache intermedie non possono farlo.
  • public: qualsiasi cache può archiviare la risposta.

Consulta l'Appendice: diagramma di flusso Cache-Control per visualizzare il processo per decidere quali valori di Cache-Control utilizzare. Cache-Control può anche accettare un elenco di istruzioni separate da virgole. Consulta Appendice: esempi di Cache-Control.

Anche l'impostazione di ETag o Last-Modified può essere utile. Come indicato nelle intestazioni della risposta, ETag e Last-Modified hanno entrambi lo stesso scopo: determinare se il browser deve scaricare di nuovo un file memorizzato nella cache che è scaduto. Ti consigliamo di utilizzare ETag perché è più preciso.

Esempio di tag ETag

Supponiamo che siano trascorsi 120 secondi dal recupero iniziale e che il browser abbia avviato una nuova richiesta per la stessa risorsa. In primo luogo, il browser controlla la cache HTTP e trova la risposta precedente. Sfortunatamente, il browser non può utilizzare la risposta precedente perché è scaduta. A questo punto, il browser può inviare una nuova richiesta e recuperare la nuova risposta completa. Tuttavia, ciò non è efficiente perché se la risorsa non è cambiata, non c'è motivo di scaricare di nuovo le informazioni già presenti nella cache.
Questo è il problema per cui i token di convalida ETag sono progettati per risolvere. Il server genera e restituisce un token arbitrario, che in genere è un hash o qualche altra fingerprint dei contenuti del file. Il browser non ha bisogno di sapere come viene generata l'impronta. Deve solo inviarlo al server alla richiesta successiva. Se l'impronta è ancora la stessa, la risorsa non è cambiata e il browser può saltare il download.

L'impostazione di ETag o Last-Modified rende la richiesta di riconvalida molto più efficiente consentendo di attivare le intestazioni delle richieste If-Modified-Since o If-None-Match menzionate in Intestazioni delle richieste.

Quando un server web configurato correttamente rileva le intestazioni delle richieste in entrata, può confermare se la versione della risorsa che il browser ha già nella sua cache HTTP corrisponde all'ultima versione sul server web. Se viene rilevata una corrispondenza, il server può rispondere con una risposta HTTP 304 Not Modified, che equivale a dire "Continua a usare i contenuti che hai già". I dati da trasferire quando si invia questo tipo di risposta sono davvero scarsi, quindi di solito è molto più rapido che dover inviare una copia della risorsa effettiva richiesta.

Diagramma di un client che richiede una risorsa e del server che risponde con un&#39;intestazione 304.
Il browser richiede /file al server e include l'intestazione If-None-Match per indicare al server di restituire il file completo solo se il valore ETag del file sul server non corrisponde al valore If-None-Match del browser. In questo caso, i valori corrispondono, quindi il server restituisce una risposta 304 Not Modified con le istruzioni per il periodo di tempo massimo per cui il file deve essere memorizzato nella cache (Cache-Control: max-age=120).

Riepilogo

La cache HTTP è un modo efficace per migliorare le prestazioni del caricamento perché riduce le richieste di rete non necessarie. È supportato in tutti i browser e la configurazione non richiede troppo lavoro.

Le seguenti configurazioni di Cache-Control sono un buon inizio:

  • Cache-Control: no-cache per le risorse che devono essere riconvalidate con il server prima di ogni utilizzo.
  • Cache-Control: no-store per le risorse che non devono mai essere memorizzate nella cache.
  • Cache-Control: max-age=31536000 per le risorse sottoposte al controllo delle versioni.

L'intestazione ETag o Last-Modified può aiutarti a riconvalidare le risorse cache scadute in modo più efficiente.

Scopri di più

Se stai cercando di andare oltre le nozioni di base sull'utilizzo dell'intestazione Cache-Control, consulta la guida Best practice per la memorizzazione nella cache e max-age gotchas di Jake Archibald.

Consulta Ama la cache per istruzioni su come ottimizzare l'utilizzo della cache per i visitatori di ritorno.

Appendice: Altri suggerimenti

Se hai più tempo, ecco altri modi per ottimizzare l'utilizzo della cache HTTP:

  • Utilizza URL coerenti. Se pubblichi gli stessi contenuti su URL diversi, il browser recupera e memorizza quei contenuti più volte.
  • Riduci al minimo il tasso di abbandono. Se parte di una risorsa (ad esempio un file CSS) viene aggiornata di frequente, mentre il resto del file no (come nel caso del codice della libreria), valuta la possibilità di suddividere il codice che viene aggiornato di frequente in un file separato e di utilizzare una strategia di memorizzazione nella cache di breve durata per il codice che si aggiorna di frequente e una strategia di memorizzazione nella cache lunga per il codice che non cambia spesso.
  • Se il tuo criterio Cache-Control presenta un grado di inattività accettabile, prendi in considerazione la nuova direttiva stale-while-revalidate .

Appendice: diagramma di flusso Cache-Control

Diagramma di flusso
Il processo decisionale per l'impostazione delle intestazioni Cache-Control.

Appendice: esempi Cache-Control

Valore Cache-Control Spiegazione
max-age=86400 La risposta può essere memorizzata nella cache dai browser e dalle cache intermedie per un massimo di un giorno (60 secondi x 60 minuti x 24 ore).
private, max-age=600 La risposta può essere memorizzata nella cache dal browser, ma non da cache intermedie, per un massimo di dieci minuti (60 secondi x 10 minuti).
public, max-age=31536000 La risposta può essere archiviata in qualsiasi cache per un anno.
no-store La risposta non può essere memorizzata nella cache e deve essere recuperata per intero a ogni richiesta.