Busting della cache tramite params


123

Vogliamo memorizzare il busto nella cache sulle distribuzioni di produzione, ma non sprecare un sacco di tempo per trovare un sistema per farlo. Il mio pensiero era di applicare un parametro alla fine dei file css e js con il numero di versione corrente:

<link rel="stylesheet" href="base_url.com/file.css?v=1.123"/>

Due domande: questo romperà efficacemente la cache? Il parametro farà sì che il browser non memorizzi mai nella cache la risposta da quell'URL poiché il parametro indica che si tratta di contenuto dinamico?

Risposte:


115

Il parametro ?v=1.123indica una stringa di query e il browser quindi penserà che si tratta di un nuovo percorso da, ad esempio,?v=1.0 . Così facendo si carica dal file, non dalla cache. Come vuoi.

E il browser presumerà che la fonte rimarrà la stessa la prossima volta che chiami ?v=1.123e dovrebbe metterla nella cache con quella stringa. Quindi rimarrà memorizzato nella cache, indipendentemente dalla configurazione del server, finché non ti sposti ?v=1.124o così via.


4
Citando Steve Souders: "Per ottenere il vantaggio della memorizzazione nella cache da parte di proxy popolari, evitare di girare con una stringa di query e invece rivedere il nome del file stesso." La spiegazione completa può essere trovata qui: stevesouders.com/blog/2008/08/23/…
lao

25
Quel post sul blog si avvicina ormai a un decennio fa. Pensi che i fornitori di cache e i CDN debbano ancora accoglierlo? Squid sembra essere in grado di memorizzare nella cache i documenti con stringhe di query ora .
jeteon

1
Forse questo aiuta qualcuno: Personalmente, uso il timestamp di modifica del file come parametro di versione "automatico", ad es. <link rel="stylesheet" href="style.css?v=1487935578" />
oelna

Personalmente non capisco perché, ma Lara Hogan (Swanson) (responsabile tecnico di Etsy) non consiglia di utilizzare i parametri di query per il busting della cache. Penso che abbia a che fare con i proxy della cache tra l'utente e il server.
Sam Rueby

36

Due domande: questo romperà efficacemente la cache?

Sì. Anche Stack Overflow usa questo metodo, anche se ricordo che loro (con i loro milioni di visitatori al giorno e zilioni di diverse versioni e configurazioni di client e proxy) hanno avuto alcuni casi limite in cui anche questo non era sufficiente per rompere la cache. Ma il presupposto generale è che questo funzionerà ed è un metodo adatto per interrompere la memorizzazione nella cache sui client.

Il parametro farà sì che il browser non memorizzi mai nella cache la risposta da quell'URL poiché il parametro indica che si tratta di contenuto dinamico?

No. Il parametro non cambierà la politica di memorizzazione nella cache; le intestazioni di memorizzazione nella cache inviate dal server si applicano ancora e, se non ne invia, le impostazioni predefinite del browser.


1
@spender Non riesco a trovare il riferimento in questo momento, temo, c'era un lungo articolo sul blog o una risposta SO in cui Jeff Atwood ne parla (IIRC)
Pekka

2
@spender Ho letto che alcuni server proxy (vecchi o configurabili) ignorano la stringa di query durante la memorizzazione nella cache.
MrWhite

2
@spender - ho sentito la stessa cosa e penso che cambiare il nome del file o il percorso sia l'opzione migliore. Potrebbe essere più semplice lasciare spostare tutti i tuoi file statici sotto un nome di cartella con versione, ad esempio /static/v22/file.css, poiché potresti fare più file con una singola cartella rinominata, ad esempio /static/v23/file.csse/static/v23/mystuff.js
Brad Parks

22

È più sicuro inserire il numero di versione nel nome file effettivo. Ciò consente di esistere più versioni contemporaneamente in modo da poter distribuire una nuova versione e se esistono ancora pagine HTML memorizzate nella cache che richiedono la versione precedente, otterranno la versione che funziona con il loro HTML.

Nota, in una delle più grandi distribuzioni con versione ovunque su Internet, jQuery utilizza i numeri di versione nel nome file effettivo e consente in modo sicuro la coesistenza di più versioni senza alcuna logica lato server speciale (ogni versione è solo un file diverso).

Questa operazione interrompe la cache una volta quando si distribuiscono nuove pagine e nuovi file collegati (che è ciò che si desidera) e da quel momento in poi quelle versioni possono essere effettivamente memorizzate nella cache (cosa che si desidera anche).


Sono d'accordo con questo, ma è molto più facile che Sinatra aggiunga? V = <% = VERSION%> a tutte le richieste css e js invece di dover controllare ogni file individualmente. Alla fine passeremo a sinatra-assetpack, che pre-elaborerà e comprimerà tutti i file e in realtà aggiungerà una versione # al nome del file, che ci permetterà di controllarli individualmente molto più facilmente.
Brad Herman

1
Sono d'accordo che inserire il numero di versione nel nome del file è la soluzione più sicura se vuoi essere sicuro al 10000%, ma non seguo l'argomento "più versioni per esistere contemporaneamente". Un URL con un parametro di query è distinto dallo stesso URL con un parametro di query diverso. Dovrebbero essere trattati come due diverse risorse dal cliente; se non lo sono, il cliente è rotto.
Pekka

2
@Pekka: il numero di versione può consentire l'esistenza di più versioni contemporaneamente, ma ciò richiede la cooperazione del server per mappare il parametro della query al file effettivo corretto. Non credo che questo sia ciò che l'OP sta facendo qui e ci sono poche ragioni per richiedere tale complicazione quando la modifica del nome del file è molto più semplice e non richiede la cooperazione del server. Ovviamente entrambi possono funzionare.
jfriend00

11

Come altri hanno già detto, il busting della cache con un parametro di query è solitamente considerato una cattiva idea (tm) ed è stato per molto tempo. È meglio riflettere la versione nel nome del file. Html5 Boilerplate sconsiglia di utilizzare la stringa di query, tra le altre.

Detto questo, delle raccomandazioni che ho visto che hanno citato una fonte, sembrano tutte prendere la loro saggezza da un articolo del 2008 di Steve Souders. Le sue conclusioni si basano sul comportamento dei delegati in quel momento e possono o meno essere rilevanti in questi giorni. Tuttavia, in assenza di informazioni più aggiornate, la modifica del nome del file è l'opzione sicura.


9

Romperà la cache una volta, dopo che il client ha scaricato la risorsa, ogni altra risposta verrà fornita dalla cache del client a meno che:

  1. il parametro v viene aggiornato.
  2. il client svuota la cache

6

In generale dovrebbe andare bene, ma è possibile che non funzioni se è presente una cache intermedia (un proxy) configurata per ignorare i parametri della richiesta.

Ad esempio, se si fornisce contenuto statico tramite Akamai CDN, è possibile configurarlo per ignorare i parametri di richiesta per impedire il busting della cache utilizzando questo metodo.


5

Dipende molto da quanto robusto vuoi che sia il tuo caching. Ad esempio, il server proxy squid (e forse altri) per impostazione predefinita non memorizza nella cache gli URL serviti con una stringa di query - almeno, lo ha fatto quando l'articolo è stato scritto. Se non ti dispiace alcuni casi d'uso che causano inutili mancate cache, vai avanti con i parametri di query. Ma è molto facile impostare uno schema di busting della cache basato sul nome del file che eviti questo problema.


5
Il proxy squid citato nell'articolo di Steve Souders ha modificato la politica di memorizzazione nella cache predefinita. Dalla versione 2.7 (maggio 2008) e versione 3.1 (marzo 2010), il comportamento predefinito prevede la cache del contenuto dinamico.
Josh Rack

5

Trovato un confronto delle 2 tecniche (stringa di query vs nome file) qui :

La versione come stringa di query presenta due problemi.

In primo luogo, potrebbe non essere sempre un browser che implementa il caching attraverso il quale dobbiamo rompere. Si dice che alcuni proxy (forse più vecchi) ignorino la stringa di query rispetto al loro comportamento di memorizzazione nella cache.

In secondo luogo, in alcuni scenari di distribuzione più complessi, in cui si dispone di più frontend e / o più server di backend, un aggiornamento è tutt'altro che istantaneo. Devi essere in grado di pubblicare contemporaneamente sia la vecchia che la nuova versione delle tue risorse. Guarda ad esempio come questo influisce su di te quando utilizzi Google App Engine.


4

Un altro approccio simile consiste nell'usare htaccess mod_rewrite per ignorare parte del percorso quando si servono i file. La tua pagina indice mai memorizzata nella cache fa riferimento al percorso più recente dei file.

Dal punto di vista dello sviluppo è facile come usare i parametri per il numero di versione, ma è robusto quanto l'approccio del nome del file.

Utilizzare la parte ignorata del percorso per il numero di versione e il server lo ignora e serve il file non memorizzato nella cache.

1.2.3/css/styles.cssserve lo stesso file da css/styles.cssquando la prima directory è stata rimossa e ignorata dal file htaccess

Compresi i file con versione

<?php
  $version = "1.2.3";
?>

<html>
  <head>
    <meta http-equiv="cache-control" content="max-age=0" />
    <meta http-equiv="cache-control" content="no-cache" />
    <meta http-equiv="expires" content="0" />
    <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
    <meta http-equiv="pragma" content="no-cache" />
    <link rel="stylesheet" type="text/css" href="<?php echo $version ?>/css/styles.css">
  </head>
  <body>
    <script src="<?php echo $version ?>/js/main.js"></script>
  </body>
</html>

Tieni presente che questo approccio significa che devi disabilitare la memorizzazione nella cache della tua pagina indice. Utilizzando i tag <meta> per disattivare la memorizzazione nella cache in tutti i browser?

.htaccess file

RewriteEngine On

# if you're requesting a file that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-f 
# likewise if a directory that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-d 

# otherwise, rewrite foo/bar/baz to bar/baz - ignore the first directory
RewriteRule ^[^/]+/(.+)$ $1 [L] 

Puoi adottare lo stesso approccio su qualsiasi piattaforma server che consente la riscrittura degli URL

(condizione di riscrittura adattata da mod_rewrite - riscrive la directory alla stringa di query tranne / #! / )

... e se hai bisogno del busting della cache per la tua pagina di indice / punto di ingresso del sito, puoi sempre utilizzare JavaSript per aggiornarlo.


2
<script type="text/javascript">
// front end cache bust

var cacheBust = ['js/StrUtil.js', 'js/protos.common.js', 'js/conf.js', 'bootstrap_ECP/js/init.js'];   
for (i=0; i < cacheBust.length; i++){
     var el = document.createElement('script');
     el.src = cacheBust[i]+"?v=" + Math.random();
     document.getElementsByTagName('head')[0].appendChild(el);
}
</script> 

Durante lo sviluppo / test di nuove versioni, la cache può essere un problema perché il browser, il server e anche a volte la telco 3G (se si esegue la distribuzione mobile) memorizzerà nella cache il contenuto statico (ad esempio JS, CSS, HTML, img). Puoi ovviare a questo problema aggiungendo il numero di versione, il numero casuale o il timestamp all'URL, ad esempio: JSP: <script src = "js / excel.js? Time = <% = new java.util.Date ()%>"> </ script> Nel caso in cui tu stia eseguendo HTML puro (invece delle pagine del server JSP, ASP, PHP) il server non ti aiuterà. Nel browser, i collegamenti vengono caricati prima che venga eseguito JS, quindi è necessario rimuovere i collegamenti e caricarli con JS
Conete Cristian

Non penso che questo caricherà i file JS in ordine, in modo sincrono.
Stealth Rabbi

0
 <script>
    var storedSrcElements = [
         "js/exampleFile.js",
         "js/sampleFile.js",
         "css/style.css"
          ];

    var head= document.getElementsByTagName('head')[0];
    var script;
    var link;
    var versionNumberNew = 4.6;

    for(i=0;i<storedSrcElements.length;i++){
     script= document.createElement('script');
     script.type= 'text/javascript';
     script.src= storedSrcElements[i] + "?" + versionNumberNew;
     head.appendChild(script);
    }     


     </script> 


       ### Change the version number  (versionNumberNew) when you want the new files to be loaded  ###

0

Spero che questo dovrebbe aiutarti a iniettare file JS esterno

<script type="text/javascript"> 
var cachebuster = Math.round(new Date().getTime() / 1000); 
document.write('<scr'+'ipt type="text/javascript" src="external.js?cb=' +cachebuster+'"></scr' + 'ipt>');
</script>

Sorgente: codice cachebuster in JavaScript

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.