Gestione della cache del browser in app a pagina singola


27

Sto cercando di capire come gestire correttamente la cache del browser Web per le app a pagina singola.

Ho un design abbastanza tipico: diversi file HTML, JS e CSS che implementano la SPA e un sacco di dati JSON che vengono consumati dalla SPA. I problemi sorgono quando voglio inviare un aggiornamento: aggiorno la parte statica del sito e il codice che genera JSON allo stesso tempo, ma i browser client hanno spesso la parte statica memorizzata nella cache, quindi il vecchio codice tenta di elaborare i nuovi dati e può (a seconda delle modifiche apportate) incorrere in problemi. (In particolare, IE sembra più aggressivo di Chrome o Firefox sull'utilizzo di JS memorizzato nella cache senza riconvalidare.)

Qual è il modo migliore per gestirlo?

  1. Assicurati che le mie modifiche JSON siano compatibili con le versioni precedenti e supponi che le cache del browser scadano entro un lasso di tempo ragionevole.
  2. Incorporare una sorta di numero di versione sia nel JS statico che nel JSON, quindi eseguire window.location.reload(true);se non corrispondono.
  3. Capire la combinazione appropriata di intestazioni ( must-revalidateo no-cachequalsiasi altra cosa; le fonti variano su come farlo) per garantire che i browser riconvalidino sempre tutte le risorse su ogni carico, anche se ciò significa qualche round trip extra per caricare il sito.
  4. Gestisci il mio controllo cache e scade le intestazioni in modo che il contenuto statico scada quando voglio inviare un aggiornamento.
  5. Qualcos'altro?

1
Ho sentito che i comandi n. 3 e n. 4 falliscono inaspettatamente nei controlli del browser Web incorporato se l'ambiente è dannoso ( tosse iOS) da parte dei colleghi. # 1 e # 2 possono essere una scelta a livello di app, ma potrebbero comunque (?) Causare problemi di cache per altre risorse o per carichi parziali di risorse. L'unica cosa che ho visto funzionare in modo affidabile nel codice pronto per la produzione è recuperare yoururl.html? <SomeTimeStamp> poiché questo falsificherà la maggior parte dei meccanismi di memorizzazione nella cache. Bonus: ruota l'intera app Web in un file in modo che i carichi abbiano successo o meno atomicamente. Unico inconveniente: funziona meglio su un collegamento locale. Il tuo chilometraggio può variare. In bocca al lupo!
J Trana,

2
+1 all'utilizzo di un numero di versione o di un timestamp come parametro URL per le risorse.
9000

Risposte:


14

Hai bisogno di una soluzione di busting della cache . Il ruolo del busting della cache è:

  1. Rinomina le risorse con un nome univoco a seconda del loro contenuto.
  2. Aggiorna tutti i riferimenti a tali risorse.

In un progetto basato su Grunt è comune utilizzare grunt-rev per garantire che a tutti i file che devono essere aggiornati vengano assegnati nomi univoci, in base al loro contenuto.

Se ti assicuri che i tuoi file JSON ottengano i nomi dei file di busting della cache insieme ai riferimenti ad essi nel tuo Javascript, i client caricheranno sempre i file JSON previsti dal Javascript.

Il vantaggio della denominazione dei file basata su hash è che i file che non sono stati modificati avranno gli stessi nomi di file dopo il busting della cache, quindi i browser possono continuare a utilizzare in sicurezza il contenuto memorizzato nella cache quando non è cambiato.

Ovviamente questo è il tipo di cose che vuoi automatizzare come parte della build di produzione del tuo progetto, quindi non devi tenere traccia della modifica manuale di nomi di file e riferimenti.


2
+1 per il bit "busting della cache" in corsivo, che apre le porte a Google in modo produttivo queste cose.
Zak Kus,

@Ted Percival - yeoman framework fa questo, che io uso, ma sto vedendo un problema. quando rilascio una nuova build, il browser potrebbe avere index.html memorizzato nella cache con riferimenti ai vecchi file ... e il browser riceve un errore. come devo risolvere questo? (A.) collega simbolicamente tutti i vecchi nomi di file a quelli nuovi (funziona) (B.) aggiungi l'intestazione no-cache a index.html (ma è sempre rispettato) (C.) aggiungi .htaccess per riconoscere un file revved e cerca quello di base (es. 12345.main.js -> main.js)
timh,

5

È possibile utilizzare if-modified-since + last-modifiedo if-none-match + etagintestazioni insieme all'intestazione corretta cache-control. (Possono esserci bug del browser , ma nulla che non puoi gestire nei browser recenti.)

Se i file sono statici, ti suggerisco di usarlo if-modified-since, perché può essere fatto automaticamente con un server HTTP ben configurato. Dovrebbe restituire 304 se il file non è stato modificato dall'ultimo download.

Non credo che i tuoi # 1 e # 2 funzionerebbero a lungo termine. Il numero 3 o il numero 4 possono funzionare. Il n. 3 è più semplice, ma devi imparare come affrontare questo problema solo una volta. Quindi proverei il numero 4 se fossi in te, ma la soluzione potrebbe dipendere da quali browser utilizzano i tuoi clienti ... Ad esempio IE8 ha problemi aggiornando la cache ajax, ecc ...


2

Se puoi includere Java Servlet Filter nella tua SPA, ecco una soluzione funzionante: CorrectBrowserCacheHandlerFilter.java

Fondamentalmente, quando il browser richiede i file statici, il server reindirizzerà tutte le richieste allo stesso ma con un parametro di query hash ( ?v=azErTad esempio) che dipende dal contenuto del file statico di destinazione.

In questo modo, il browser non memorizzerà mai nella cache i file statici dichiarati nel tuo index.htmlesempio (perché riceverà sempre a 302 Moved Temporarily), ma memorizzerà nella cache solo quelli con la versione hash (il server risponderà 200per loro). Quindi la cache del browser verrà utilizzata in modo efficiente per quei file statici con versione hash.

Disclaimer: sono l'autore di CorrectBrowserCacheHandlerFilter.java.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.