Cache-Busting über Parameter

121

Wir möchten die Pleite bei Produktionsbereitstellungen zwischenspeichern, aber nicht viel Zeit damit verschwenden, ein System dafür zu finden. Mein Gedanke war, einen Parameter auf das Ende von CSS- und JS-Dateien mit der aktuellen Versionsnummer anzuwenden:

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

Zwei Fragen: Wird dies den Cache effektiv brechen? Verursacht der Parameter, dass der Browser die Antwort von dieser URL niemals zwischenspeichert, da der Parameter angibt, dass es sich um dynamischen Inhalt handelt?

Brad Herman
quelle

Antworten:

115

Der Parameter ?v=1.123gibt eine Abfragezeichenfolge an, und der Browser wird daher annehmen , dass es sich beispielsweise um einen neuen Pfad handelt ?v=1.0. Dadurch wird es aus der Datei geladen, nicht aus dem Cache. Wie du willst.

Der Browser geht davon aus, dass die Quelle beim nächsten Aufruf unverändert bleibt, ?v=1.123und sollte sie mit dieser Zeichenfolge zwischenspeichern. Es bleibt also zwischengespeichert, unabhängig davon, wie Ihr Server eingerichtet ist, bis Sie zu ?v=1.124oder so weitergehen.

Marshall
quelle
4
Zitat von Steve Souders: "Um den Vorteil des Caching durch beliebte Proxys zu nutzen, vermeiden Sie es, mit einem Querystring zu drehen, und revidieren Sie stattdessen den Dateinamen selbst." Die vollständige Erklärung finden Sie hier: stevesouders.com/blog/2008/08/23/…
lao
25
Dieser Blog-Beitrag nähert sich jetzt einem Jahrzehnt. Denken Sie, dass Cache-Anbieter und CDNs dies noch nicht tun? Squid scheint jetzt in der Lage zu sein, Dokumente mit Abfragezeichenfolgen zwischenzuspeichern .
Jeteon
1
Vielleicht hilft das jemandem: Persönlich verwende ich den Zeitstempel für die Dateiänderung als 'automatischen' Versionsparameter, z. <link rel="stylesheet" href="style.css?v=1487935578" />
Oelna
Ich persönlich verstehe nicht warum, aber Lara Hogan (Swanson) (technische Leiterin bei Etsy) empfiehlt nicht, Abfrageparameter für das Cache-Busting zu verwenden. Ich denke, es hat mit Cache-Proxys zwischen dem Benutzer und dem Server zu tun.
Sam Rueby
36

Zwei Fragen: Wird dies den Cache effektiv brechen?

Ja. Sogar Stack Overflow verwendet diese Methode, obwohl ich mich daran erinnere, dass sie (mit ihren Millionen Besuchern pro Tag und zig verschiedenen Client- und Proxy-Versionen und -Konfigurationen) einige ungewöhnliche Fälle hatten, in denen selbst dies nicht ausreichte, um den Cache zu brechen. Die allgemeine Annahme ist jedoch, dass dies funktioniert und eine geeignete Methode ist, um das Caching auf Clients zu unterbrechen.

Verursacht der Parameter, dass der Browser die Antwort von dieser URL niemals zwischenspeichert, da der Parameter angibt, dass es sich um dynamischen Inhalt handelt?

Nein. Der Parameter ändert die Caching-Richtlinie nicht. Die vom Server gesendeten Caching-Header gelten weiterhin. Wenn keine gesendet werden, werden die Standardeinstellungen des Browsers verwendet.

Pekka
quelle
1
@spender Ich kann die Referenz momentan nicht finden Ich fürchte, es gab einen langen Blog-Artikel oder eine SO-Antwort, in der Jeff Atwood darüber spricht (IIRC)
Pekka
2
@spender Ich habe gelesen, dass einige Proxyserver (entweder alt oder konfigurierbar) die Abfragezeichenfolge beim Zwischenspeichern ignorieren.
MrWhite
2
@spender - ich habe das gleiche gehört und ich denke, das Ändern des Dateinamens oder des Pfades ist die beste Option. Es ist möglicherweise am einfachsten, alle statischen Dateien unter einem versionierten Ordnernamen zu verschieben /static/v22/file.css, da Sie beispielsweise mehrere Dateien mit einem einzigen Ordner umbenennen können, z. B. /static/v23/file.cssund/static/v23/mystuff.js
Brad Parks
22

Es ist sicherer, die Versionsnummer in den tatsächlichen Dateinamen einzufügen. Auf diese Weise können mehrere Versionen gleichzeitig vorhanden sein, sodass Sie eine neue Version bereitstellen können. Wenn noch zwischengespeicherte HTML-Seiten vorhanden sind, die die ältere Version anfordern, erhalten sie die Version, die mit ihrem HTML funktioniert.

Beachten Sie, dass jQuery in einer der größten versionierten Bereitstellungen im Internet Versionsnummern im tatsächlichen Dateinamen verwendet und es sicher ermöglicht, dass mehrere Versionen ohne spezielle serverseitige Logik nebeneinander existieren (jede Version ist nur eine andere Datei).

Dies sprengt den Cache einmal, wenn Sie neue Seiten und neue verknüpfte Dateien bereitstellen (was Sie möchten), und von da an können diese Versionen effektiv zwischengespeichert werden (was Sie auch möchten).

jfriend00
quelle
Ich bin damit einverstanden, aber es ist viel einfacher, Sinatra? V = <% = VERSION%> an alle CSS- und JS-Anforderungen anhängen zu lassen, als jede Datei einzeln steuern zu müssen. Schließlich werden wir zu sinatra-assetpack wechseln, das alle Dateien vorverarbeitet und komprimiert und tatsächlich eine Versionsnummer an den Dateinamen anfügt, wodurch wir sie dann viel einfacher einzeln steuern können.
Brad Herman
1
Ich bin damit einverstanden, dass das Einfügen der Versionsnummer in den Dateinamen die ultimative sicherste Lösung ist, wenn Sie 10000% sicher sein möchten, aber ich folge nicht dem Argument "Mehrere Versionen müssen gleichzeitig existieren". Eine URL mit einem Abfrageparameter unterscheidet sich von derselben URL mit einem anderen Abfrageparameter. Sie sollten vom Kunden als zwei verschiedene Ressourcen behandelt werden. Ist dies nicht der Fall, ist der Client defekt.
Pekka
2
@Pekka - Mit der Versionsnummer können mehrere Versionen gleichzeitig vorhanden sein. Dies erfordert jedoch die Zusammenarbeit des Servers, um den Abfrageparameter der richtigen tatsächlichen Datei zuzuordnen. Ich denke nicht, dass dies das ist, was das OP hier tut, und es gibt wenig Grund, diese Komplikation beim Ändern des Dateinamens zu fordern, ist viel einfacher und erfordert keine Serverzusammenarbeit. Natürlich können beide funktionieren.
jfriend00
11

Wie andere gesagt haben, wird Cache-Busting mit einem Abfrageparameter normalerweise als schlechte Idee (Bad Idea, TM) angesehen, und das schon lange. Es ist besser, die Version im Dateinamen wiederzugeben. Html5 Boilerplate empfiehlt unter anderem, die Abfragezeichenfolge nicht zu verwenden.

Von den Empfehlungen, die ich gesehen habe und die eine Quelle zitierten, scheinen alle ihre Weisheit einem Artikel von Steve Souders aus dem Jahr 2008 zu entnehmen. Seine Schlussfolgerungen basieren auf dem Verhalten der Stimmrechtsvertreter zu diesem Zeitpunkt und können heutzutage relevant sein oder auch nicht. In Ermangelung aktuellerer Informationen ist das Ändern des Dateinamens die sichere Option.

Hashwechsel
quelle
9

Der Cache wird einmal gelöscht, nachdem der Client die Ressource heruntergeladen hat. Jede zweite Antwort wird aus dem Client-Cache bereitgestellt, es sei denn:

  1. Der Parameter v wird aktualisiert.
  2. Der Client löscht den Cache
ncremins
quelle
6

Im Allgemeinen sollte dies in Ordnung sein, aber es ist möglich, dass dies nicht funktioniert, wenn ein Zwischencache (ein Proxy) vorhanden ist, der so konfiguriert ist, dass die Anforderungsparameter ignoriert werden.

Wenn Sie beispielsweise statischen Inhalt über Akamai CDN bereitstellen, kann dieser so konfiguriert werden, dass Anforderungsparameter ignoriert werden, um zu verhindern, dass der Cache mit dieser Methode beschädigt wird.

Ken Liu
quelle
5

Es hängt sehr davon ab, wie robust Ihr Caching sein soll. Zum Beispiel kann der Squid - Proxy - Server (und möglicherweise anderen) standardmäßig nicht das Caching URLs mit einem Abfragezeichenfolgeflag serviert - zumindest taten es , wenn dieser Artikel geschrieben wurde. Wenn Ihnen bestimmte Anwendungsfälle, die unnötige Cache-Fehler verursachen, nichts ausmachen, fahren Sie mit den Abfrageparametern fort. Es ist jedoch sehr einfach, ein auf Dateinamen basierendes Cache-Busting-Schema einzurichten, das dieses Problem vermeidet.

Bobby Jack
quelle
5
Der im Artikel von Steve Souders zitierte Squid-Proxy hat seine Standard-Caching-Richtlinie geändert. Seit Version 2.7 (Mai 2008) und Version 3.1 (März 2010) wird standardmäßig dynamischer Inhalt zwischengespeichert.
Josh Rack
5

Hier wurde ein Vergleich der beiden Techniken (Abfragezeichenfolge und Dateiname) gefunden :

Die Version als Querystring hat zwei Probleme.

Erstens ist es möglicherweise nicht immer ein Browser, der das Caching implementiert, über das wir pleite gehen müssen. Es wird gesagt, dass bestimmte (möglicherweise ältere) Proxys den Querystring hinsichtlich ihres Caching-Verhaltens ignorieren.

Zweitens ist in bestimmten komplexeren Bereitstellungsszenarien, in denen Sie mehrere Frontend- und / oder mehrere Backend-Server haben, ein Upgrade alles andere als sofort. Sie müssen in der Lage sein, sowohl die alte als auch die neue Version Ihres Assets gleichzeitig bereitzustellen. Sehen Sie zum Beispiel, wie sich dies auf Sie auswirkt, wenn Sie Google App Engine verwenden.

Benutzer
quelle
4

Ein anderer ähnlicher Ansatz besteht darin, htaccess mod_rewrite zu verwenden, um einen Teil des Pfads beim Bereitstellen der Dateien zu ignorieren. Ihre nie zwischengespeicherte Indexseite verweist auf den neuesten Pfad zu den Dateien.

Aus entwicklungspolitischer Sicht ist es so einfach wie die Verwendung von Parametern für die Versionsnummer, aber es ist genauso robust wie der Dateinamenansatz.

Verwenden Sie den ignorierten Teil des Pfads für die Versionsnummer. Der Server ignoriert ihn einfach und stellt die nicht zwischengespeicherte Datei bereit.

1.2.3/css/styles.cssdient der gleichen Datei wie css/styles.cssseit dem Entfernen des ersten Verzeichnisses, das von der htaccess-Datei ignoriert wird

Einschließlich versionierter Dateien

<?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>

Beachten Sie, dass dieser Ansatz bedeutet, dass Sie das Caching Ihrer Indexseite deaktivieren müssen. Verwenden Sie <meta> -Tags, um das Caching in allen Browsern zu deaktivieren ?

.htaccess-Datei

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] 

Sie können auf jeder Serverplattform, die das Umschreiben von URLs ermöglicht, denselben Ansatz wählen

(Umschreibbedingung von mod_rewrite angepasst - Verzeichnis umschreiben, um Zeichenfolge außer / #! / abzufragen )

... und wenn Sie Cache-Busting für Ihre Indexseite / Ihren Site-Einstiegspunkt benötigen, können Sie diese jederzeit mit JavaSript aktualisieren .

Alexanderbird
quelle
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> 
Conete Cristian
quelle
Während der Entwicklung / des Testens neuer Versionen kann der Cache ein Problem sein, da der Browser, der Server und manchmal sogar die 3G-Telekommunikation (wenn Sie eine mobile Bereitstellung durchführen) den statischen Inhalt (z. B. JS, CSS, HTML, img) zwischenspeichern. Sie können dies überwinden, indem Sie Versionsnummer, Zufallszahl oder Zeitstempel an die URL anhängen, z. B.: JSP: <script src = "js / excel.js? Time = <% = new java.util.Date ()%>"> </ Skript> Wenn Sie reines HTML ausführen (anstelle von Serverseiten JSP, ASP, PHP), hilft Ihnen der Server nicht weiter. Im Browser werden Links geladen, bevor der JS ausgeführt wird. Daher müssen Sie die Links entfernen und mit JS
Conete Cristian am
Ich glaube nicht, dass dadurch die JS-Dateien der Reihe nach synchron geladen werden.
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  ###
Teja
quelle
0

Ich hoffe, dies sollte Ihnen helfen, eine externe JS-Datei einzufügen

<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>

Quelle - Cachebuster-Code in JavaScript

Vinit Kadkol
quelle