Wie kann man den Browser zwingen, zwischengespeicherte CSS / JS-Dateien neu zu laden?

993

Ich habe festgestellt, dass einige Browser (insbesondere Firefox und Opera) sehr eifrig zwischengespeicherte Kopien von CSS- und JS- Dateien verwenden, selbst zwischen Browsersitzungen. Dies führt zu einem Problem, wenn Sie eine dieser Dateien aktualisieren, der Browser des Benutzers die zwischengespeicherte Kopie jedoch weiterhin verwendet.

Die Frage ist: Was ist die eleganteste Methode, um den Browser des Benutzers zu zwingen, die Datei neu zu laden, wenn sie geändert wurde?

Im Idealfall würde die Lösung den Browser nicht zwingen, die Datei bei jedem Besuch der Seite neu zu laden. Ich werde meine eigene Lösung als Antwort veröffentlichen, aber ich bin gespannt, ob jemand eine bessere Lösung hat, und ich werde Ihre Stimmen entscheiden lassen.

Update:

Nachdem ich hier eine Weile die Diskussion zugelassen habe, habe ich den Vorschlag von John Millikin und da5id als nützlich empfunden . Es stellt sich heraus, dass es dafür einen Begriff gibt: Auto-Versionierung .

Ich habe unten eine neue Antwort veröffentlicht, die eine Kombination aus meiner ursprünglichen Lösung und Johns Vorschlag darstellt.

Eine andere Idee, die von SCdF vorgeschlagen wurde, wäre das Anhängen einer gefälschten Abfragezeichenfolge an die Datei. (Einige Python-Codes zur automatischen Verwendung des Zeitstempels als gefälschte Abfragezeichenfolge wurden von pi gesendet .) Es gibt jedoch einige Diskussionen darüber, ob der Browser eine Datei mit einer Abfragezeichenfolge zwischenspeichern würde oder nicht. (Denken Sie daran, dass der Browser die Datei zwischenspeichern und bei zukünftigen Besuchen verwenden soll. Wir möchten, dass die Datei erst dann wieder abgerufen wird, wenn sie geändert wurde.)

Da nicht klar ist, was mit einer gefälschten Abfragezeichenfolge passiert, akzeptiere ich diese Antwort nicht.

Pmpr
quelle
Ich habe dies in meinem .htaccess und nie irgendwelche Probleme mit zwischengespeicherten Dateien : ExpiresActive On ExpiresDefault "modification".
Frank Conijn
2
Ich würde definitiv zustimmen, dass das Hinzufügen von Versionsinformationen zur URL der Datei bei weitem der beste Weg ist. Es funktioniert die ganze Zeit für alle. Aber wenn Sie es nicht verwenden und nur diese eine CSS- oder JS-Datei gelegentlich in Ihrem eigenen Browser neu laden müssen ... öffnen Sie es einfach in einem eigenen Tab und drücken Sie UMSCHALT-Neu laden (oder STRG-F5)! Sie können dasselbe effektiv mit JS tun, indem Sie eine Datei in einen (versteckten) Iframe laden, warten, bis sie geladen wird, und dann aufrufen iframe.contentWindow.location.reload(true). Siehe Methode (4) von stackoverflow.com/a/22429796/999120 - das sind Bilder, aber das Gleiche gilt.
Doin
2
Ich schätze die Art und Weise, wie diese Frage gestellt wurde und seitdem aktualisiert wurde, sehr. Es wurde vollständig beschrieben, was ich in den Antworten erwarten sollte. Ich werde diesen Ansatz von nun an in meinen Fragen verfolgen. Prost!
rd22

Antworten:

455

Update: Umgeschrieben, um Vorschläge von John Millikin und da5id aufzunehmen . Diese Lösung ist in PHP geschrieben, sollte aber leicht an andere Sprachen angepasst werden können.

Update 2: Einbeziehen von Kommentaren von Nick Johnson, dass der ursprüngliche .htaccessreguläre Ausdruck Probleme mit Dateien wie verursachen kann json-1.3.js. Die Lösung besteht darin, nur dann neu zu schreiben, wenn am Ende genau 10 Ziffern vorhanden sind. (Da 10 Ziffern alle Zeitstempel vom 09.09.2001 bis 20.11.2286 abdecken.)

Zunächst verwenden wir in .htaccess die folgende Umschreiberegel:

RewriteEngine on
RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ $1.$2 [L]

Jetzt schreiben wir die folgende PHP-Funktion:

/**
 *  Given a file, i.e. /css/base.css, replaces it with a string containing the
 *  file's mtime, i.e. /css/base.1221534296.css.
 *  
 *  @param $file  The file to be loaded.  Must be an absolute path (i.e.
 *                starting with slash).
 */
function auto_version($file)
{
  if(strpos($file, '/') !== 0 || !file_exists($_SERVER['DOCUMENT_ROOT'] . $file))
    return $file;

  $mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $file);
  return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $file);
}

Ändern Sie jetzt, wo immer Sie Ihr CSS einfügen, Folgendes:

<link rel="stylesheet" href="/css/base.css" type="text/css" />

Dazu:

<link rel="stylesheet" href="<?php echo auto_version('/css/base.css'); ?>" type="text/css" />

Auf diese Weise müssen Sie das Link-Tag nie wieder ändern, und der Benutzer sieht immer das neueste CSS. Der Browser kann die CSS-Datei zwischenspeichern. Wenn Sie jedoch Änderungen an Ihrem CSS vornehmen, wird dies vom Browser als neue URL angezeigt, sodass die zwischengespeicherte Kopie nicht verwendet wird.

Dies kann auch mit Bildern, Favoriten und JavaScript funktionieren. Grundsätzlich alles, was nicht dynamisch generiert wird.

Pennen
quelle
16
Mein eigener statischer Inhaltsserver macht genau das Gleiche, außer dass ich einen Parameter für die Versionierung (base.css? V = 1221534296) anstelle einer Dateinamenänderung (base.1221534296.css) verwende. Ich vermute, Ihr Weg ist vielleicht ein bisschen effizienter. Sehr cool.
Jens Roland
4
@ Kip: Sehr raffinierte Lösung. Das Umschreiben von URLs hat offensichtlich viel mehr zu bieten als nur hübsche URLs.
James P.
37
Ich sehe ein Problem damit, dass es viele Male auf das Dateisystem zugreift - genau - Anzahl der Links * Anzahl der Anfragen / Sek. ... das kann ein Problem für Sie sein oder auch nicht.
Tomáš Fejfar
3
@AlixAxel: Nein, Browser rufen es erneut ab, wenn sich der Parameter ändert, aber einige öffentliche Proxys speichern keine Dateien mit URL-Parametern zwischen. Daher empfiehlt es sich, die Version in den Pfad aufzunehmen. Und der Overhead von mod_rewrite ist im Vergleich zu jedem anderen Leistungsengpass in WPO
Jens Roland
8
Ist die erste file_existsÜberprüfung wirklich notwendig? filemtimewird bei einem Fehler false zurückgeben. Warum also nicht einfach den Wert für die Dateizeit einer Variablen zuweisen und prüfen, ob er falsch ist, bevor die Datei umbenannt wird? Das würde eine unnötige Dateioperation reduzieren, die sich wirklich summieren würde.
Gavin
184

Einfache clientseitige Technik

Im Allgemeinen ist das Caching gut. Es gibt also einige Techniken, je nachdem, ob Sie das Problem bei der Entwicklung einer Website selbst beheben oder ob Sie versuchen, den Cache in einer Produktionsumgebung zu steuern.

Allgemeine Besucher Ihrer Website haben nicht die gleiche Erfahrung wie bei der Entwicklung der Website. Da der durchschnittliche Besucher weniger häufig auf die Website kommt (möglicherweise nur einige Male im Monat, es sei denn, Sie sind ein Google- oder ein hi5-Netzwerk), ist es weniger wahrscheinlich, dass sich Ihre Dateien im Cache befinden, und das kann ausreichen. Wenn Sie eine neue Version in den Browser erzwingen möchten, können Sie der Anforderung jederzeit eine Abfragezeichenfolge hinzufügen und die Versionsnummer erhöhen, wenn Sie größere Änderungen vornehmen:

<script src="/myJavascript.js?version=4"></script>

Dadurch wird sichergestellt, dass jeder die neue Datei erhält. Dies funktioniert, weil der Browser anhand der URL der Datei ermittelt, ob sich eine Kopie im Cache befindet. Wenn Ihr Server nicht für die Abfragezeichenfolge eingerichtet ist, wird diese ignoriert, der Name sieht für den Browser jedoch wie eine neue Datei aus.

Wenn Sie jedoch eine Website entwickeln, möchten Sie die Versionsnummer nicht jedes Mal ändern, wenn Sie eine Änderung an Ihrer Entwicklungsversion speichern. Das wäre langweilig.

Während Sie Ihre Site entwickeln, besteht ein guter Trick darin, automatisch einen Abfragezeichenfolgenparameter zu generieren:

<!-- Development version: -->
<script>document.write('<script src="/myJavascript.js?dev=' + Math.floor(Math.random() * 100) + '"\><\/script>');</script>

Das Hinzufügen einer Abfragezeichenfolge zur Anforderung ist eine gute Möglichkeit, eine Ressource zu versionieren. Für eine einfache Website ist dies jedoch möglicherweise nicht erforderlich. Und denken Sie daran, Caching ist eine gute Sache.

Es ist auch erwähnenswert, dass der Browser nicht unbedingt geizig ist, wenn es darum geht, Dateien im Cache zu halten. Browser haben Richtlinien für diese Art von Dingen und spielen normalerweise nach den Regeln, die in der HTTP-Spezifikation festgelegt sind. Wenn ein Browser eine Anfrage an einen Server stellt, ist ein Teil der Antwort ein EXPIRES-Header. Ein Datum, das dem Browser mitteilt, wie lange er im Cache aufbewahrt werden soll. Wenn der Browser das nächste Mal auf eine Anforderung für dieselbe Datei stößt, stellt er fest, dass sich eine Kopie im Cache befindet, und prüft anhand des Ablaufdatums, ob diese verwendet werden soll.

Ob Sie es glauben oder nicht, es ist tatsächlich Ihr Server, der den Browser-Cache so dauerhaft macht. Sie könnten Ihre Servereinstellungen anpassen und die EXPIRES-Header ändern, aber die kleine Technik, die ich oben geschrieben habe, ist wahrscheinlich eine viel einfachere Möglichkeit, dies zu tun. Da das Caching gut ist, möchten Sie dieses Datum normalerweise weit in die Zukunft setzen (ein "Far-Future Expires Header") und die oben beschriebene Technik verwenden, um eine Änderung zu erzwingen.

Wenn Sie an weiteren Informationen zu HTTP interessiert sind oder wissen möchten, wie diese Anfragen gestellt werden, ist ein gutes Buch "High Performance Web Sites" von Steve Souders. Es ist eine sehr gute Einführung in das Thema.

Keparo
quelle
3
Der schnelle Trick, mit Javascript eine Abfragezeichenfolge zu generieren, funktioniert während der aktiven Entwicklung hervorragend. Ich habe das gleiche mit PHP gemacht.
Alan Turing
2
Dies ist der einfachste Weg, um das gewünschte Ergebnis des Originalplakats zu erzielen. Die mod_rewrite-Methode funktioniert gut, wenn Sie jedes Mal, wenn Sie die Seite laden, ein erneutes Laden der CSS- oder JS-Datei erzwingen möchten. Diese Methode ermöglicht weiterhin das Zwischenspeichern, bis Sie die Datei tatsächlich ändern und wirklich möchten, dass sie neu geladen wird.
Scott80109
@keparo, ich habe reichlich Anzahl der Anfragen auf allen Seiten, wenn ich dies manuell ändern werde, wird es einen Monat dauern. Wenn Sie mir helfen können, alles zu lösen, ohne auf jede Seite zu codieren.
Cracker
1
Dies scheint für mein CSS nicht zu funktionieren, wenn ich <link href='myCss.css?dev=14141'...>
Folgendes
3
Dies ist keine praktikable Lösung. Eine gute Anzahl von Browsern weigert sich einfach, irgendetwas mit einer Abfragezeichenfolge zwischenzuspeichern. Dies ist der Grund, warum Google, GTMetrix und ähnliche Tools ein Flag auslösen, wenn Sie Abfragezeichenfolgen für Verweise auf statischen Inhalt haben. Während es sicherlich eine anständige Lösung für die Entwicklung ist, ist es absolut keine Lösung für die Produktion. Außerdem steuert der Browser das Caching, nicht den Server. Der Server EMPFIEHLT einfach, wann er aktualisiert werden soll. Ein Browser MUSS nicht auf den Server hören (und oft auch nicht). Mobile Geräte sind dafür ein Paradebeispiel.
Nate I
113

Googles mod_pagespeed Plugin von für Apache führt für Sie eine automatische Versionierung durch. Es ist wirklich glatt.

Es analysiert HTML auf dem Weg aus dem Webserver (funktioniert mit PHP, Rails, Python, statischem HTML - alles) und schreibt Links zu CSS, JS und Bilddateien neu, sodass sie einen ID-Code enthalten. Es stellt die Dateien unter den geänderten URLs mit einer sehr langen Cache-Kontrolle bereit. Wenn sich die Dateien ändern, werden die URLs automatisch geändert, sodass der Browser sie erneut abrufen muss. Es funktioniert im Grunde nur ohne Änderungen an Ihrem Code. Es wird sogar Ihren Code auf dem Weg nach draußen minimieren.

Leopd
quelle
1
Das ist großartig, aber immer noch in der Beta. Kann es für den Unternehmensdienst verwendet werden?
Sanghyun Lee
26
Dies ist FALSCH (automatisches Fummeln mit der Quelle), wenn es sich eindeutig um ein Browserproblem handelt. Geben Sie uns (Entwicklern) eine echte Gehirn-Wipe-Aktualisierung: <ctrl> + F5
T4NK3R
25
mod_pagespeed entspricht funktional einem vollautomatischen Build / Compile-Schritt für Ihr HTML / CSS / JS. Ich denke, es wird Ihnen schwer fallen, ernsthafte Entwickler zu finden, die glauben, dass Build-Systeme an sich falsch sind oder dass irgendetwas falsch daran ist, dass sie vollständig automatisch sind. Die Analogie eines sauberen Builds besteht darin, den Cache von mod_pagespeed zu löschen: code.google.com/p/modpagespeed/wiki/… ?
Leopd
3
@ T4NK3R mod_pagespeed muss nichts mit Ihrer Quelle tun, um die Cache-Verwaltung durchzuführen. Es wurde lediglich erwähnt, dass es bei Dingen wie der Minimierung helfen kann . Ob es "FALSCH" ist oder nicht, das ist völlig subjektiv. Es mag für Sie falsch sein, aber das bedeutet nicht, dass es instinktiv schlecht ist .
Madbreaks
2
Es funktioniert auch mit Nginx, obwohl Sie es aus dem Quellcode erstellen müssen: developer.google.com/speed/pagespeed/module/…
Rohit
93

Anstatt die Version manuell zu ändern, würde ich empfehlen, einen MD5-Hash der eigentlichen CSS-Datei zu verwenden.

Ihre URL wäre also so etwas wie

http://mysite.com/css/[md5_hash_here]/style.css

Sie können weiterhin die Umschreiberegel verwenden, um den Hash zu entfernen. Der Vorteil besteht jedoch darin, dass Sie Ihre Cache-Richtlinie jetzt auf "Für immer zwischenspeichern" setzen können. Wenn die URL identisch ist, bedeutet dies, dass die Datei unverändert bleibt.

Sie können dann ein einfaches Shell-Skript schreiben, das den Hash der Datei berechnet und Ihr Tag aktualisiert (Sie möchten es wahrscheinlich zur Aufnahme in eine separate Datei verschieben).

Führen Sie dieses Skript einfach jedes Mal aus, wenn sich CSS ändert, und Sie sind gut. Der Browser lädt Ihre Dateien NUR neu, wenn sie geändert werden. Wenn Sie eine Bearbeitung vornehmen und diese dann rückgängig machen, müssen Sie problemlos herausfinden, zu welcher Version Sie zurückkehren müssen, damit Ihre Besucher sie nicht erneut herunterladen können.

Levik
quelle
1
Leider weiß ich nicht, wie ich es umsetzen soll. Beratung bitte ... weitere Details ...
Michael Phelps
Eine Implementierung in Shell, Ruby usw. wäre großartig
Peter
3
Sehr schöne Lösung ... aber ich denke, es ist ressourcenintensiv, den Hash der Datei in jeder Dateianforderung (CSS, JS, Bilder, HTML usw.) für jeden einzelnen Seitenbesuch zu berechnen.
DeepBlue
Dies ist eine Standardlösung für Benutzer von js oder css, die mit gulp, grunt oder webpack gebündelt werden. Die Implementierung ist für jede Lösung unterschiedlich. Das Hashing Ihrer Dateien als Erstellungsschritt ist jedoch üblich und wird für moderne gebündelte Apps empfohlen
Brandon Søren Culley,
@DeepBlue - Die Antwort lautet "Führen Sie dieses Skript jedes Mal aus, wenn sich CSS ändert" . Das ist NICHT bei jedem Seitenbesuch. OTOH Die Antwort lässt wichtige Details aus - wie wird der geänderte Hash Teil der URL? Ich weiß nicht ...
ToolmakerSteve
70

Ich bin mir nicht sicher, warum ihr so ​​viel Mühe habt, diese Lösung zu implementieren.

Alles, was Sie tun müssen, um den geänderten Zeitstempel der Datei abzurufen und als Querystring an die Datei anzuhängen

In PHP würde ich es tun als:

<link href="mycss.css?v=<?= filemtime('mycss.css') ?>" rel="stylesheet">

filemtime ist eine PHP-Funktion, die den zeitlich geänderten Zeitstempel zurückgibt.

Phantom007
quelle
Sie können einfach verwenden mycss.css?1234567890.
Gavin
3
Sehr elegant, obwohl ich es leicht modifiziert habe <link rel="stylesheet" href="mycss.css?<?php echo filemtime('mycss.css') ?>"/>, nur für den Fall, dass einige der Argumente in diesem Thread zum Zwischenspeichern von
URLs
Nach meinem letzten Kommentar habe ich gesehen, dass WordPress verwendet, ?ver=also wer weiß!
luke_mclachlan
Tolle Lösung. Außerdem stellte ich fest, dass die Dateizeit für einen vollqualifizierten Domänennamen (FQDN) nicht funktioniert, sodass ich den vollqualifizierten Domänennamen für den href-Teil und $ _SERVER ["DOCUMENT_ROOT"] für den filemtime-Teil verwendete. EX: <link rel = "stylesheet" href = "http: //theurl/mycss.css? V = <? Php echo filemtime ($ _ SERVER [" DOCUMENT_ROOT "]. '/Mycss.css')?>" />
rrtx2000
Vielen Dank. Einfach und gut. Hier ist es in Python: progpath = os.path.dirname (sys.argv [0]) def versionize (Datei): timestamp = os.path.getmtime ('% s /../ web /% s'% (progpath , Datei)) return '% s? v =% s'% (Datei, Zeitstempel) print <link href = "% s" rel = "Stylesheet" '' type = "text / css" /> '\% versionize ( 'css / main.css')
dlink
52

Sie können einfach ?foo=1234am Ende Ihres CSS / JS-Imports setzen und 1234 so ändern, dass es Ihnen gefällt. Schauen Sie sich die SO-HTML-Quelle als Beispiel an.

Die Idee da ist, dass die? Parameter werden bei der Anforderung ohnehin verworfen / ignoriert, und Sie können diese Nummer ändern, wenn Sie eine neue Version einführen.


Hinweis: Es gibt einige Argumente dafür, wie sich dies genau auf das Caching auswirkt. Ich glaube, der allgemeine Kern davon ist, dass GET-Anfragen mit oder ohne Parameter sollten cachable sein, so sollte die obige Lösung arbeiten.

Es liegt jedoch sowohl am Webserver, zu entscheiden, ob er diesen Teil der Spezifikation einhalten möchte, als auch am Browser, den der Benutzer verwendet, da er einfach weitermachen und trotzdem nach einer neuen Version fragen kann.

SCdF
quelle
Unsinn. Die Abfragezeichenfolge (auch bekannt als GET-Parameter) ist Teil der URL. Sie können und werden zwischengespeichert. Dies ist eine gute Lösung.
Troelskn
9
@troelskn: Die HTTP 1.1-Spezifikation sagt etwas anderes aus (in Bezug auf GET- und HEAD-Anforderungen mit Abfrageparametern): Caches dürfen Antworten auf solche URIs NICHT als frisch behandeln, es sei denn, der Server gibt eine explizite Ablaufzeit an. Siehe w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.9
Michael Johnson
4
Ich habe versucht, die Versionierung der Abfragezeichenfolge mit allen gängigen Browsern durchzuführen, und sie speichern die Datei, die Spezifikationen oder nicht. Ich denke jedoch, dass es besser ist, das Format style.TIMESTAMP.css zu verwenden, ohne Abfragezeichenfolgen zu missbrauchen, da es immer noch die Möglichkeit gibt, dass das Zwischenspeichern von Proxy-Software die Datei NICHT zwischenspeichert.
Tomas Andrle
34
Erwähnenswert ist aus irgendeinem Grund, dass Stackoverflow selbst die Abfragezeichenfolgenmethode verwendet.
Jason
2
Haben Sie überprüft, dass die Verwendung von? = Parameter nicht dazu führt, dass Browser zwischengespeicherte Dateien erneut abrufen, wenn sich Parameter ändern. Der einzige Weg ist , den Dateinamen selbst programmatisch auf der Serverseite zu ändern , wie von Kip beantwortet
arunskrish
41

Ich habe gehört, dass dies "Auto-Versionierung" genannt wird. Die gebräuchlichste Methode besteht darin, die mtime der statischen Datei irgendwo in die URL aufzunehmen und sie mithilfe von Umschreibhandlern oder URL-Confs zu entfernen:

Siehe auch:

John Millikin
quelle
3
Vielen Dank, ich denke, dies war ein weiterer Fall, in dem meine Idee diskutiert wurde. Ich wusste einfach nicht, wie sie heißt, also habe ich sie bei Google-Suchen nie gefunden.
Kip
27

Die rund 30 vorhandenen Antworten sind ein guter Rat für eine Website von ca. 2008. Wenn es jedoch um eine moderne Single-Page-Anwendung (SPA) geht, ist es möglicherweise an der Zeit, einige grundlegende Annahmen zu überdenken… insbesondere die Idee, dass der Webserver nur die einzige, neueste Version von a bereitstellen soll Datei.

Stellen Sie sich vor, Sie sind ein Benutzer, der Version M eines SPA in Ihren Browser geladen hat:

  1. Ihre CD-Pipeline stellt die neue Version N der Anwendung auf dem Server bereit
  2. Sie navigieren innerhalb des SPA, das eine XHR an den Server sendet, um sie abzurufen /some.template
    • (Ihr Browser hat die Seite nicht aktualisiert, daher wird weiterhin Version M ausgeführt. )
  3. Der Server antwortet mit dem Inhalt von /some.template- Möchten Sie, dass er Version M oder N der Vorlage zurückgibt?

Wenn das Format /some.templatezwischen den Versionen M und N geändert wurde (oder die Datei umbenannt wurde oder was auch immer) , möchten Sie wahrscheinlich nicht, dass Version N der Vorlage an den Browser gesendet wird, in dem die alte Version M des Parsers ausgeführt wird . †

Bei Web-Apps tritt dieses Problem auf, wenn zwei Bedingungen erfüllt sind:

  • Ressourcen werden irgendwann nach dem ersten Laden der Seite asynchron angefordert
  • Die App-Logik setzt Dinge (die sich in zukünftigen Versionen ändern können) bezüglich des Ressourceninhalts voraus

Sobald Ihre App mehrere Versionen gleichzeitig bereitstellen muss, ist das Lösen von Caching und "Neuladen" trivial:

  1. Installieren Sie alle Site-Dateien in versionierten Verzeichnissen : /v<release_tag_1>/…files…,/v<release_tag_2>/…files…
  2. Stellen Sie HTTP-Header so ein, dass Browser Dateien für immer zwischenspeichern
    • (Oder noch besser, legen Sie alles in ein CDN)
  3. Aktualisieren Sie alle <script>und <link>Tags usw., um auf diese Datei in einem der versionierten Verzeichnisse zu verweisen

Dieser letzte Schritt klingt schwierig, da möglicherweise ein URL-Builder für jede URL in Ihrem serverseitigen oder clientseitigen Code aufgerufen werden muss. Oder Sie können das <base>Tag einfach geschickt nutzen und die aktuelle Version an einer Stelle ändern.

† Eine Möglichkeit, dies zu umgehen, besteht darin, den Browser aggressiv zu zwingen, alles neu zu laden, wenn eine neue Version veröffentlicht wird. Um laufende Vorgänge abschließen zu können, ist es möglicherweise immer noch am einfachsten, mindestens zwei Versionen parallel zu unterstützen: v-current und v-previous.

Michael Kropat
quelle
Michael - dein Kommentar ist sehr relevant. Ich versuche hier genau, eine Lösung für mein SPA zu finden. Ich habe einige Hinweise bekommen, musste aber selbst eine Lösung finden. Am Ende war ich sehr zufrieden mit dem, was ich mir ausgedacht habe, also schrieb ich einen Blog-Beitrag und eine Antwort auf diese Frage (einschließlich Code). Vielen Dank für die Hinweise
Statler
Toller Kommentar. Ich kann es nicht verstehen, während die Leute immer wieder über Cache-Busting und HTTP-Caching als echte Lösung für Probleme beim Zwischenspeichern von Websites sprechen, ohne die neuen Probleme von SPAs zu kommentieren, als wäre dies ein Randfall.
David Casillas
1
Hervorragende Resonanz und absolut ideale Strategie! Und Bonuspunkte für die Erwähnung des baseTags! Was die Unterstützung von altem Code betrifft: Dies ist nicht immer eine Möglichkeit, noch ist es immer eine gute Idee. Neue Codeversionen unterstützen möglicherweise das Brechen von Änderungen an anderen Teilen einer App oder beinhalten Notfallkorrekturen, Schwachstellen-Patches usw. Ich habe diese Strategie noch nicht selbst implementiert, aber ich war immer der Meinung, dass die Gesamtarchitektur es ermöglichen sollte, dass Bereitstellungen eine alte Version als obsoletekennzeichnen und beim nächsten asynchronen Aufruf ein erneutes Laden erzwingen (oder einfach alle Sitzungen über WebSockets zwangsweise deaktivieren) ).
Jonny Asmar
Schön, eine gut durchdachte Antwort in Bezug auf Anwendungen mit nur einer Seite zu sehen.
Nate I
Das ist "blaugrüne Bereitstellung", wenn Sie nach weiteren Informationen suchen möchten.
Fil
15

Verwenden Sie nicht foo.css? Version = 1! Browser dürfen URLs nicht mit GET-Variablen zwischenspeichern. Laut http://www.thinkvitamin.com/features/webapps/serving-javascript-fast ignorieren Opera und Safari dies, IE und Firefox jedoch nicht! Verwenden Sie stattdessen foo.v1234.css und entfernen Sie die Versionsnummer mithilfe von Umschreiberegeln.

Airrob
quelle
1
Erstens zwischenspeichern Browser nicht, das ist eine Funktion von HTTP. Warum sollte sich http für die Struktur eines URI interessieren? Gibt es einen offiziellen Verweis auf eine Spezifikation, die besagt, dass das HTTP-Cache die Semantik eines URI verstehen sollte, damit keine Elemente mit einer Abfragezeichenfolge zwischengespeichert werden?
AnthonyWJones
13
Ein Webbrowser, der die Funktionalität zum Zwischenspeichern von Objekten enthält (überprüfen Sie das Cache-Verzeichnis Ihres Browsers). HTTP ist ein Protokoll, das Anweisungen von Servern an Clients (Proxys, Browser, Spider usw.) enthält, die eine Cache-Steuerung vorschlagen.
tzot
13

In Laravel (PHP) können wir dies auf klare und elegante Weise tun (unter Verwendung des Zeitstempels für Dateimodifikationen):

<script src="{{ asset('/js/your.js?v='.filemtime('js/your.js')) }}"></script>

Und ähnlich für CSS

<link rel="stylesheet" href="{{asset('css/your.css?v='.filemtime('css/your.css'))}}">

Beispiel für eine HTML-Ausgabe ( filemtimeRückgabezeit als Unix-Zeitstempel )

<link rel="stylesheet" href="assets/css/your.css?v=1577772366">
Kamil Kiełczewski
quelle
Was ist die Ausgabe dieses Befehls in HTML? Und was ist, wenn ich nur Versionen wie? V = 3 ,? V = 4 usw. erneuern muss? - Erzwingt nicht, dass der Browser jedes Mal CSS lädt, wenn der Benutzer die Website betritt
Gediminas
Dateizeit : "Diese Funktion gibt die Zeit zurück, zu der die Datenblöcke einer Datei geschrieben wurden, dh die Zeit, zu der der Inhalt der Datei geändert wurde." src: php.net/manual/en/function.filemtime.php
Kamil Kiełczewski
11

Die RewriteRule benötigt ein kleines Update für JS- oder CSS-Dateien, die am Ende eine Versionierung mit Punktnotation enthalten. ZB json-1.3.js.

Ich habe dem regulären Ausdruck eine Punktnegationsklasse [^.] Hinzugefügt, also .number. wird ignoriert.

RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]
Nick Johnson
quelle
2
Danke für die Eingabe! Seit ich diesen Beitrag geschrieben habe, bin ich auch davon verbrannt worden. Meine Lösung bestand darin, nur dann neu zu schreiben, wenn der letzte Teil des Dateinamens genau zehn Ziffern enthält. (10 Ziffern decken alle Zeitstempel vom 09.09.2001 bis 20.11.2286 ab.) Ich habe meine Antwort aktualisiert, um diesen regulären Ausdruck aufzunehmen:^(.*)\.[\d]{10}\.(css|js)$ $1.$2
Kip
Ich verstehe Regex, aber ich verstehe nicht, mit welchem ​​Problem Sie hier lösen [^.]. Es hat auch keinen Vorteil, \dinnerhalb einer Zeichenklasse zu schreiben - es \d+wird dasselbe tun. Wie veröffentlicht, stimmt Ihr Muster mit einer beliebigen Anzahl von Zeichen (gierig) überein, dann mit einem wörtlichen Punkt, dann mit einem Nicht-Punkt, dann mit einer oder mehreren Ziffern, dann mit einem Punkt, dann cssoder jsdann mit dem Ende des Dateinamens. Keine Übereinstimmung für Ihre Beispieleingabe: regex101.com/r/RPGC62/1
mickmackusa
10

Für ASP.NET 4.5 und höher können Sie die Skriptbündelung verwenden .

Die Anforderung http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81bezieht sich auf das Bundle AllMyScripts und enthält ein Abfragezeichenfolgenpaar v = r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81. Die Abfragezeichenfolge v hat ein Werttoken, das eine eindeutige Kennung ist, die für das Caching verwendet wird. Solange sich das Bundle nicht ändert, fordert die ASP.NET-Anwendung das AllMyScripts-Bundle mit diesem Token an. Wenn sich eine Datei im Bundle ändert, generiert das ASP.NET-Optimierungsframework ein neues Token, das sicherstellt, dass Browseranforderungen für das Bundle das neueste Bundle erhalten.

Das Bündeln bietet weitere Vorteile, einschließlich einer höheren Leistung beim erstmaligen Laden von Seiten mit Minimierung.

user3738893
quelle
Bitte helfen Sie mir, dass ich keine Änderungen in bundle.config vornehme, sondern nur in CSS- oder JS-Dateien. Wie kann ich dann das Caching-Problem beheben?
Vedankita Kumbhar
10

Hier ist eine reine JavaScript-Lösung

(function(){

    // Match this timestamp with the release of your code
    var lastVersioning = Date.UTC(2014, 11, 20, 2, 15, 10);

    var lastCacheDateTime = localStorage.getItem('lastCacheDatetime');

    if(lastCacheDateTime){
        if(lastVersioning > lastCacheDateTime){
            var reload = true;
        }
    }

    localStorage.setItem('lastCacheDatetime', Date.now());

    if(reload){
        location.reload(true);
    }

})();

Oben wird nach dem letzten Besuch des Benutzers auf Ihrer Website gesucht. Wenn der letzte Besuch vor der Veröffentlichung des neuen Codes stattgefunden hat location.reload(true), wird die Seitenaktualisierung vom Server erzwungen.

Normalerweise habe ich dies als erstes Skript innerhalb des Skripts, <head>damit es ausgewertet wird, bevor andere Inhalte geladen werden. Wenn ein Neuladen erforderlich ist, fällt dies dem Benutzer kaum auf.

Ich verwende lokalen Speicher, um den Zeitstempel für den letzten Besuch im Browser zu speichern, aber Sie können dem Mix Cookies hinzufügen, wenn Sie ältere Versionen von IE unterstützen möchten.

Lloyd Banks
quelle
Ich habe so etwas versucht, dies funktioniert nur auf der neu geladenen Seite, aber wenn die Site mehrere Seiten hat, die dieselben CSS / Bilder teilen, verwenden andere Seiten immer noch alte Ressourcen.
DeepBlue
9

Interessanter Beitrag. Nachdem ich alle Antworten hier gelesen habe, zusammen mit der Tatsache, dass ich nie Probleme mit "falschen" Abfragezeichenfolgen hatte (was ich nicht sicher bin, warum jeder dies so ungern verwendet), schätze ich die Lösung (die die Notwendigkeit von Apache-Umschreibungsregeln beseitigt wie in der akzeptierten Antwort) besteht darin, einen kurzen HASH des CSS-Dateiinhalts (anstelle der Datei datetime) als gefälschten Querystring zu berechnen.

Dies würde Folgendes ergeben:

<link rel="stylesheet" href="/css/base.css?[hash-here]" type="text/css" />

Natürlich erledigen die datetime-Lösungen auch die Aufgabe beim Bearbeiten einer CSS-Datei, aber ich denke, es geht um den Inhalt der CSS-Datei und nicht um die datetime-Datei. Warum sollten diese also verwechselt werden?

Michiel
quelle
8

Für meine Entwicklung finde ich, dass Chrom eine großartige Lösung hat.

https://developer.chrome.com/devtools/docs/tips-and-tricks#hard-reload

Klicken Sie bei geöffneten Entwicklertools einfach lange auf die Schaltfläche "Aktualisieren" und lassen Sie sie los, sobald Sie den Mauszeiger über "Leeren Cache und Hard Reload" bewegen.

Dies ist mein bester Freund und ein superleichter Weg, um das zu bekommen, was Sie wollen!

Frank Bryce
quelle
Wenn Sie Chrome als Entwicklungsumgebung verwenden, besteht eine andere nicht-invasive Lösung darin, den Cache zu deaktivieren: Unter "Einstellungen" können Sie den Festplatten-Cache ungültig machen, indem Sie "Cache deaktivieren" auswählen (Hinweis: Die DevTools müssen sichtbar / geöffnet sein damit dies funktioniert).
Velojet
7

Vielen Dank bei Kip für seine perfekte Lösung!

Ich habe es erweitert, um es als Zend_view_Helper zu verwenden. Da mein Client seine Seite auf einem virtuellen Host ausführt, habe ich sie auch dafür erweitert.

Hoffe, es hilft auch jemand anderem.

/**
 * Extend filepath with timestamp to force browser to
 * automatically refresh them if they are updated
 *
 * This is based on Kip's version, but now
 * also works on virtual hosts
 * @link http://stackoverflow.com/questions/118884/what-is-an-elegant-way-to-force-browsers-to-reload-cached-css-js-files
 *
 * Usage:
 * - extend your .htaccess file with
 * # Route for My_View_Helper_AutoRefreshRewriter
 * # which extends files with there timestamp so if these
 * # are updated a automatic refresh should occur
 * # RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]
 * - then use it in your view script like
 * $this->headLink()->appendStylesheet( $this->autoRefreshRewriter($this->cssPath . 'default.css'));
 *
 */
class My_View_Helper_AutoRefreshRewriter extends Zend_View_Helper_Abstract {

    public function autoRefreshRewriter($filePath) {

        if (strpos($filePath, '/') !== 0) {

            // path has no leading '/'
            return $filePath;
        } elseif (file_exists($_SERVER['DOCUMENT_ROOT'] . $filePath)) {

            // file exists under normal path
            // so build path based on this
            $mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $filePath);
            return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $filePath);
        } else {

            // fetch directory of index.php file (file from all others are included)
            // and get only the directory
            $indexFilePath = dirname(current(get_included_files()));

            // check if file exist relativ to index file
            if (file_exists($indexFilePath . $filePath)) {

                // get timestamp based on this relativ path
                $mtime = filemtime($indexFilePath . $filePath);

                // write generated timestamp to path
                // but use old path not the relativ one
                return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $filePath);
            } else {

                return $filePath;
            }
        }
    }

}

Prost und danke.

Lony
quelle
7

Haben den clientseitigen DOM-Ansatz nicht gefunden, der das Skriptknoten- (oder CSS-) Element dynamisch erstellt:

<script>
    var node = document.createElement("script"); 
    node.type = "text/javascript";
    node.src = 'test.js?'+Math.floor(Math.random()*999999999);
    document.getElementsByTagName("head")[0].appendChild(node);
</script>
GreQ
quelle
6

Google Chrome verfügt über die Optionen Hard Reload sowie Empty Cache und Hard Reload. Sie können auf die Schaltfläche zum erneuten Laden (im Inspektionsmodus) klicken und diese gedrückt halten, um eine auszuwählen.

ajithes111
quelle
Um zu klären, durch "Inspect - Modus", sie beziehen sich auf "Dev Tools" aka F12, auch bekannt als Strg + Shift + i, auch bekannt als ant menu> More Tools> Developer Toolsalias right click> Inspect Element. Es gibt auch eine Einstellung, die irgendwo in Entwicklungswerkzeugen vergraben ist (ich vergesse den Speicherort), um sie bei jedem Neuladen hart neu zu laden.
Jonny Asmar
5

Sie können ein "sitzungsweites Caching" erzwingen, wenn Sie die Sitzungs-ID als fehlerhaften Parameter der js / css-Datei hinzufügen:

<link rel="stylesheet" src="myStyles.css?ABCDEF12345sessionID" />
<script language="javascript" src="myCode.js?ABCDEF12345sessionID"></script>

Wenn Sie ein versionweites Caching wünschen, können Sie Code hinzufügen, um das Dateidatum oder ähnliches zu drucken. Wenn Sie Java verwenden, können Sie ein benutzerdefiniertes Tag verwenden, um den Link auf elegante Weise zu generieren.

<link rel="stylesheet" src="myStyles.css?20080922_1020" />
<script language="javascript" src="myCode.js?20080922_1120"></script>
Helios
quelle
5

Angenommen, Sie haben eine Datei verfügbar unter:

/styles/screen.css

Sie können entweder einen Abfrageparameter mit Versionsinformationen an den URI anhängen, z.

/styles/screen.css?v=1234

oder Sie können Versionsinformationen voranstellen, z.

/v/1234/styles/screen.css

IMHO ist die zweite Methode besser für CSS-Dateien, da sie unter Verwendung relativer URLs auf Bilder verweisen können. Wenn Sie also Folgendes angeben, gilt Folgendes background-image:

body {
    background-image: url('images/happy.gif');
}

Die URL lautet effektiv:

/v/1234/styles/images/happy.gif

Dies bedeutet, dass der Server beim Aktualisieren der verwendeten Versionsnummer diese als neue Ressource behandelt und keine zwischengespeicherte Version verwendet. Wenn Sie Ihre Versionsnummer auf Subversion / CVS / etc. Basieren. Revision bedeutet, dass Änderungen an Bildern, auf die in CSS-Dateien verwiesen wird, bemerkt werden. Dies ist beim ersten Schema nicht garantiert, dh die URL images/happy.gifrelativ zu /styles/screen.css?v=1235ist/styles/images/happy.gif , die keine Versionsinformationen enthält.

Ich habe eine Caching-Lösung unter Verwendung dieser Technik mit Java-Servlets implementiert und Anforderungen einfach /v/*mit einem Servlet bearbeitet, das an die zugrunde liegende Ressource (dh /styles/screen.css) delegiert . Im Entwicklungsmodus Set Caching von I - Header , die dem Client immer überprüfen , um die Frische der Ressource mit dem Server sagen (dies typischerweise in einem 304 führt , wenn Sie Tomcat delegieren DefaultServletund die .css, .jsetc. Datei nicht geändert hat) , während im Bereitstellungsmodus Ich setze Header mit der Aufschrift "Cache für immer".

Walter Rumsby
quelle
Das einfache Hinzufügen eines Ordners, den Sie bei Bedarf umbenennen können, funktioniert, wenn Sie nur relative URLs verwenden. Und dann stellen Sie sicher, dass Sie vom Basisordner in den richtigen Ordner umleiten, dh in PHP : <?php header( 'Location: folder1/login.phtml' ); ?>.
Gruber
1
Bei Verwendung der zweiten Methode macht eine Änderung an einem CSS zwischengespeicherte Kopien aller Bilder ungültig, auf die mit relativen URLs verwiesen wird, was möglicherweise wünschenswert ist oder nicht.
TomG
5

Sie können einfach eine Zufallszahl mit der CSS / JS-URL hinzufügen

example.css?randomNo=Math.random()
Ponmudi VN
quelle
5

Für ASP.NET nehme ich die nächste Lösung mit erweiterten Optionen an (Debug- / Release-Modus, Versionen):

Auf diese Weise enthaltene Js- oder CSS-Dateien:

<script type="text/javascript" src="Scripts/exampleScript<%=Global.JsPostfix%>" />
<link rel="stylesheet" type="text/css" href="Css/exampleCss<%=Global.CssPostfix%>" />

Global.JsPostfix und Global.CssPostfix werden in Global.asax folgendermaßen berechnet:

protected void Application_Start(object sender, EventArgs e)
{
    ...
    string jsVersion = ConfigurationManager.AppSettings["JsVersion"];
    bool updateEveryAppStart = Convert.ToBoolean(ConfigurationManager.AppSettings["UpdateJsEveryAppStart"]);
    int buildNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Revision;
    JsPostfix = "";
#if !DEBUG
    JsPostfix += ".min";
#endif      
    JsPostfix += ".js?" + jsVersion + "_" + buildNumber;
    if (updateEveryAppStart)
    {
        Random rand = new Random();
        JsPosfix += "_" + rand.Next();
    }
    ...
}
Ivan Kochurkin
quelle
4

Ich habe dies kürzlich mit Python gelöst. Hier der Code (sollte leicht in andere Sprachen zu übernehmen sein):

def import_tag(pattern, name, **kw):
    if name[0] == "/":
        name = name[1:]
    # Additional HTML attributes
    attrs = ' '.join(['%s="%s"' % item for item in kw.items()])
    try:
        # Get the files modification time
        mtime = os.stat(os.path.join('/documentroot', name)).st_mtime
        include = "%s?%d" % (name, mtime)
        # this is the same as sprintf(pattern, attrs, include) in other
        # languages
        return pattern % (attrs, include)
    except:
        # In case of error return the include without the added query
        # parameter.
        return pattern % (attrs, name)

def script(name, **kw):
    return import_tag("""<script type="text/javascript" """ +\
        """ %s src="/%s"></script>""", name, **kw)

def stylesheet(name, **kw):
    return import_tag('<link rel="stylesheet" type="text/css" ' +\
        """%s href="/%s">', name, **kw) 

Dieser Code hängt im Wesentlichen den Zeitstempel der Dateien als Abfrageparameter an die URL an. Der Aufruf der folgenden Funktion

script("/main.css")

wird darin enden, dass

<link rel="stylesheet" type="text/css"  href="/main.css?1221842734">

Der Vorteil ist natürlich, dass Sie Ihr HTML nie wieder ändern müssen. Wenn Sie die CSS-Datei berühren, wird automatisch eine Cache-Ungültigmachung ausgelöst. Funktioniert sehr gut und der Overhead ist nicht spürbar.

Pi.
quelle
könnte os.stat () einen Engpass verursachen?
Hoju
@Richard stat könnte ein Engpass sein, wenn die Festplatte sehr langsam ist und die Anforderungen sehr zahlreich sind. In diesem Fall können Sie den Zeitstempel irgendwo im Speicher zwischenspeichern und diesen Cache bei jeder neuen Bereitstellung löschen. Diese Komplexität wird jedoch in den meisten Anwendungsfällen nicht erforderlich sein.
pi.
4

Wenn Sie git + PHP verwenden, können Sie das Skript jedes Mal aus dem Cache neu laden, wenn sich das git-Repo mit dem folgenden Code ändert:

exec('git rev-parse --verify HEAD 2> /dev/null', $gitLog);
echo '  <script src="/path/to/script.js"?v='.$gitLog[0].'></script>'.PHP_EOL;
Readikus
quelle
4

Wenn Sie ein Entwickler sind, der das Caching vermeiden möchte, verfügt die Registerkarte "Chrome-Netzwerk" über die Option "Cache deaktivieren". Andernfalls können Sie ohne ein Server-Rendering-Framework zwei Skript-Tags verwenden.

<script type="text/javascript">
    document.write('<script type="text/javascript" src="myfile.js?q=' + Date.now() + '">
    // can't use myfile.js stuff yet
</script>')
<script type="text/javascript">
    // do something with myfile.js
</script>
astronought
quelle
4

Diese Frage ist super alt und erscheint als erstes, wenn jemand dieses Problem googelt. Dies ist keine Antwort auf die Frage, wie sie von op gewünscht wird, sondern eine Antwort auf Entwickler mit diesem Problem beim Entwickeln und Testen. Und ich kann keine neue Frage zu diesem Thema stellen, da sie als Duplikat markiert wird.

Wie viele andere wollte ich das Caching nur kurz entfernen.

"keep caching consistent with the file" .. es ist viel zu viel Aufwand ..

Im Allgemeinen macht es mir nichts aus, mehr zu laden - selbst das erneute Laden von Dateien, die sich bei den meisten Projekten nicht geändert haben - ist praktisch irrelevant. Während der Entwicklung einer App - wir laden meistens von der Festplatte localhost:port - wird dieses increase in network trafficProblem nicht als Deal Breaking-Problem eingestuft .

Die meisten kleinen Projekte spielen nur herum - sie landen nie in der Produktion. für sie brauchst du also nichts mehr ..

Wenn Sie Chrome Dev Tools verwenden , können Sie diesen Ansatz zum Deaktivieren des Caching wie in der folgenden Abbildung befolgen: wie man Chrome zwingt, zwischengespeicherte Dateien neu zu laden

Und wenn Sie Probleme mit dem Caching von Firefox haben : So erzwingen Sie das Neuladen von Assets in Firefox

So deaktivieren Sie das Caching in Firefox während der Entwicklung Wenn Sie dies nur in der Entwicklung tun, benötigen Sie auch einen Mechanismus, um das Neuladen für die Produktion zu erzwingen, da Ihre Benutzer alte Cache-ungültig gemachte Module verwenden, wenn Sie Ihre App häufig aktualisieren und keinen dedizierten Cache-Synchronisierungsmechanismus wie den in den Antworten beschriebenen bereitstellen über.

Ja, diese Informationen sind bereits in früheren Antworten enthalten, aber ich musste noch eine Google-Suche durchführen, um sie zu finden.

Hoffentlich ist diese Antwort sehr klar und jetzt müssen Sie nicht mehr.

AIon
quelle
OP fragte etwas und antwortete etwas anderes. Es geht nicht darum, das Laden lokal, sondern in der Produktion zu erzwingen, und Sie können Endbenutzer nicht bitten, den obigen Anweisungen zu folgen, um den Cache usw. zu deaktivieren.
Jitendra Pancholi
3

Es scheint, dass alle Antworten hier auf eine Art Versionierung des Namensschemas hindeuten, die ihre Nachteile hat.

Browser sollten sich darüber im Klaren sein, was zwischengespeichert werden soll und was nicht, indem sie die Antwort des Webservers lesen, insbesondere die http-Header. Wie lange ist diese Ressource gültig? Wurde diese Ressource aktualisiert, seit ich sie das letzte Mal abgerufen habe? und so weiter.

Wenn die Dinge "richtig" konfiguriert sind, sollte nur das Aktualisieren der Dateien Ihrer Anwendung (irgendwann) die Browser-Caches aktualisieren. Sie können Ihren Webserver beispielsweise so konfigurieren, dass der Browser angewiesen wird, niemals Dateien zwischenzuspeichern (was eine schlechte Idee ist).

Eine ausführlichere Erklärung, wie das funktioniert, finden Sie hier https://www.mnot.net/cache_docs/#WORK

Commonpike
quelle
3

Fügen Sie einfach diesen Code hinzu, in dem Sie ein hartes Neuladen durchführen möchten (zwingen Sie den Browser, zwischengespeicherte CSS / JS-Dateien neu zu laden). Führen Sie dies in der .load-Datei aus, damit es nicht wie eine Schleife aktualisiert wird

 $( window ).load(function() {
   location.reload(true);
});
Sandeep Ranjan
quelle
Funktioniert nicht in Chrome. Laden Sie immer noch Assets aus dem Festplatten-Cache
Jason Kim
3

Verwenden Sie einfach serverseitigen Code, um das Datum der Datei hinzuzufügen. Auf diese Weise wird sie zwischengespeichert und erst dann neu geladen, wenn sich die Datei ändert

In ASP.NET

<link rel="stylesheet" href="~/css/custom.css?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/css/custom.css")).ToString(),"[^0-9]", ""))" />

<script type="text/javascript" src="~/js/custom.js?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/js/custom.js")).ToString(),"[^0-9]", ""))"></script>    

Dies kann vereinfacht werden zu:

<script src="<%= Page.ResolveClientUrlUnique("~/js/custom.js") %>" type="text/javascript"></script>

Durch Hinzufügen einer Erweiterungsmethode zu Ihrem Projekt zum Erweitern von Seite:

public static class Extension_Methods
{
    public static string ResolveClientUrlUnique(this System.Web.UI.Page oPg, string sRelPath)
    {
        string sFilePath = oPg.Server.MapPath(sRelPath);
        string sLastDate = System.IO.File.GetLastWriteTime(sFilePath).ToString();
        string sDateHashed = System.Text.RegularExpressions.Regex.Replace(sLastDate, "[^0-9]", "");

        return oPg.ResolveClientUrl(sRelPath) + "?d=" + sDateHashed;
    }
}
Mike
quelle
2

Ich schlage vor, den folgenden Prozess zu implementieren:

  • Versionieren Sie Ihre CSS / JS-Dateien bei jeder Bereitstellung, z. B.: screen.1233.css (Die Nummer kann Ihre SVN-Revision sein, wenn Sie ein Versionsverwaltungssystem verwenden.)

  • Minimieren Sie sie, um die Ladezeiten zu optimieren

Dan Burzo
quelle