web-dev-qa-db-de.com

Cache-Busting über Params

Wir wollen Bust in Produktionsbereitstellungen zwischenspeichern, ohne jedoch eine Menge Zeit damit zu verschwenden, ein System dafür zu finden. Mein Gedanke war, einen Parameter mit der aktuellen Versionsnummer auf das Ende von css- und js-Dateien anzuwenden:

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

Zwei Fragen: Wird der Cache dadurch effektiv zerstört? Verursacht der Parameter, dass der Browser die Antwort von dieser URL niemals zwischenspeichert, da der Parameter angibt, dass es sich hierbei um dynamischen Inhalt handelt?

103
Brad Herman

Der Parameter ?v=1.123 gibt eine Abfragezeichenfolge an, und der Browser wird daher denken, dass es sich um einen neuen Pfad von ?v=1.0 handelt. 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 von ?v=1.123 und sollte mit dieser Zeichenfolge zwischengespeichert wird. Es bleibt also zwischengespeichert, Ihr Server ist jedoch eingerichtet, bis Sie zu ?v=1.124 oder so weiter wechseln.

98
Marshall

Zwei Fragen: Wird der Cache dadurch effektiv zerstört? 

Ja. Sogar Stack Overflow verwenden diese Methode, obwohl ich mich erinnere, dass sie (mit ihren Millionen Besuchern pro Tag und zig Millionen verschiedener Client- und Proxy-Versionen und -Konfigurationen) einige ausgefallene Edge-Fälle hatten, in denen selbst dies nicht ausreichte, um das zu brechen Zwischenspeicher. Die allgemeine Annahme ist jedoch, dass dies funktionieren wird, und ist eine geeignete Methode, 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 hierbei um dynamischen Inhalt handelt?

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

35
Pekka 웃

Es ist sicherer, die Versionsnummer im tatsächlichen Dateinamen anzugeben. Dadurch können mehrere Versionen gleichzeitig vorhanden sein, sodass Sie eine neue Version einführen können. Wenn noch zwischengespeicherte HTML-Seiten vorhanden sind, die die ältere Version anfordern, erhalten sie die Version, die mit ihrem HTML-Code funktioniert.

Beachten Sie, dass jQuery in einer der größten versionierten Implementierungen im Internet Versionsnummern im tatsächlichen Dateinamen verwendet, und mehrere Versionen können sicher und ohne spezielle serverseitige Logik verwendet werden (jede Version ist nur eine andere Datei).

Dadurch wird der Cache einmalig aufgehoben, wenn Sie neue Seiten und neue verknüpfte Dateien bereitstellen (was Sie möchten), und ab diesem Zeitpunkt können diese Versionen effektiv zwischengespeichert werden (was Sie auch möchten).

21
jfriend00

Wie andere bereits gesagt haben, wird das Busting von Caches mit einem Abfrageparameter seit langem als schlechte Idee angesehen. Es ist besser, die Version im Dateinamen wiederzugeben. Html5 Boilerplate rät davon ab unter anderem die Abfragezeichenfolge zu verwenden.

Von den Empfehlungen, die ich gesehen habe und die eine Quelle zitierten, scheinen jedoch alle ihre Weisheit aus einem Artikel von 2008 von Steve Souders zu beziehen. 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 jedoch die sichere Option.

11
hashchange

Nachdem der Client die Ressource heruntergeladen hat, wird jede weitere Antwort aus dem Client-Cache bereitgestellt, es sei denn:

  1. der Parameter v wird aktualisiert.
  2. der Client löscht seinen Cache
9
ncremins

Im Allgemeinen sollte dies in Ordnung sein, dies kann jedoch nicht funktionieren, wenn ein Zwischenspeicher (ein Proxy) vorhanden ist, der so konfiguriert ist, dass die Anforderungsparameter ignoriert werden.

Wenn Sie zum Beispiel statischen Inhalt über Akamai CDN bereitstellen, kann er so konfiguriert werden, dass Anforderungsparameter ignoriert werden, um zu verhindern, dass mit dieser Methode Cache-Speicher entstehen.

6
Ken Liu

Es hängt sehr davon ab, wie robust Ihr Caching sein soll. Beispiel: Der Squid-Proxy-Server (und möglicherweise auch andere) standardmäßig nicht zwischengespeichert URLs, die mit einer Abfragezeichenfolge bedient werden - zumindest es tat, als dieser Artikel geschrieben wurde. Wenn Ihnen bestimmte Anwendungsfälle, die zu unnötigen Cache-Fehlern führen, nichts ausmachen, führen Sie Abfrageparameter aus. Aber es ist sehr einfach, ein Dateinamen-basiertes Cache-Busting-Schema einzurichten, das dieses Problem vermeidet.

5
Bobby Jack

Einen Vergleich der beiden Techniken (Abfragezeichenfolge vs. Dateiname) hier gefunden: 

Version als Querstring hat zwei Probleme. 

Erstens kann es nicht immer ein Browser sein, der Caching implementiert, durch den wir brechen müssen. Es wird gesagt, dass bestimmte (möglicherweise ältere) Proxys den Querystring in Bezug auf ihr Caching-Verhalten ignorieren.

Zweitens: In bestimmten komplexeren Bereitstellungsszenarien, in denen Sie mehrere Frontend- und/oder Backend-Server haben, ist ein Upgrade alles andere als eine sofortige. Sie müssen in der Lage sein, gleichzeitig die alte und die neue Version Ihrer Assets bereitzustellen. Sehen Sie sich beispielsweise an, wie sich dies auf Sie auswirkt, wenn Sie Google App Engine verwenden.

5
user

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

Aus Entwicklungssicht ist es so einfach wie das Verwenden von Parametern für die Versionsnummer, aber es ist genauso robust wie der Dateiname-Ansatz.

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.css liefert dieselbe Datei wie css/styles.css, da das erste Verzeichnis von der htaccess-Datei entfernt und ignoriert wird

Versionierte Dateien einschließen

<?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 Zwischenspeichern Ihrer Indexseite deaktivieren müssen - Verwenden Sie <meta> -Tags, um das Zwischenspeichern 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 zulässt, denselben Ansatz verwenden

(Umschreibungsbedingung angepasst von mod_rewrite - Verzeichnis umschreiben in Abfragezeichenfolge außer/#! / )

... und wenn Sie Cache-Busting für Ihren Einstiegspunkt für Index-/Site-Sites benötigen, können Sie immer verwenden Sie JavaSript , um es zu aktualisieren. 

4
alexanderbird
<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> 
2
Conete Cristian

Hoffe, das sollte dir helfen, externe JS-Dateien einzuspritzen

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

Source - Cachebuster-Code in JavaScript

0
Vinit Kadkol
 <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
Teja