it-swarm.com.de

Wie erzwinge ich, dass der Browser zwischengespeicherte CSS/JS-Dateien neu lädt?

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

Die Frage ist: Was ist der eleganteste Weg, den Browser des Benutzers zu zwingen, die Datei neu zu laden, wenn sich die Datei geändert hat?

Idealerweise zwingt die Lösung den Browser nicht dazu, die Datei bei jedem Besuch der Seite neu zu laden. Ich werde meine eigene Lösung als Antwort posten, aber ich bin neugierig, ob jemand eine bessere Lösung hat, und ich lasse Ihre Stimmen entscheiden.

Update:

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

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

Eine andere Idee, die von SCdF vorgeschlagen wurde, wäre das Anhängen einer falschen Abfragezeichenfolge an die Datei. (Einige Python-Codes zur automatischen Verwendung des Zeitstempels, da eine falsche Abfragezeichenfolge von pi . Übergeben wurde.) 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 für zukünftige Besuche verwenden soll. Wir möchten, dass die Datei nur dann erneut abgerufen wird, wenn sie geändert wurde.)

Da nicht klar ist, was mit einer falschen Abfragezeichenfolge geschieht, akzeptiere ich diese Antwort nicht.

907
Kip

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

Update 2: Enthält Kommentare von Nick Johnson , dass der ursprüngliche .htaccess regex Probleme mit Dateien wie json-1.3.js verursachen kann. Die Lösung ist nur zu überschreiben, wenn am Ende genau 10 Ziffern stehen. (Weil 10 Ziffern alle Zeitstempel von 9.9.2001 bis 20.11.228 abdecken.)

Zuerst verwenden wir in .htaccess die folgende Umschreibungsregel:

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

Jetzt schreiben wir die folgende Funktion PHP:

/**
 *  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);
}

Wo auch immer Sie Ihr CSS einfügen, ändern Sie es wie folgt:

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

Zu diesem:

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

Auf diese Weise müssen Sie das Link-Tag nie mehr ändern, und der Benutzer sieht immer das neueste CSS. Der Browser kann die CSS-Datei zwischenspeichern, aber wenn Sie Änderungen an Ihrem CSS vornehmen, wird der Browser dies als neue URL sehen und die zwischengespeicherte Kopie nicht verwenden.

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

427
Kip

Einfache clientseitige Technik

Im Allgemeinen ist Caching gut. Es gibt also ein paar Techniken, abhängig davon, 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, die Sie beim Entwickeln der Website haben. Da der durchschnittliche Besucher seltener auf die Website kommt (möglicherweise nur ein paar Mal pro Monat, es sei denn, Sie sind ein Google- oder hi5-Netzwerk), ist die Wahrscheinlichkeit geringer, dass Ihre Dateien im Cache gespeichert werden. Wenn Sie dem Browser eine neue Version erzwingen möchten, können Sie der Anfrage immer eine Abfragezeichenfolge hinzufügen und die Versionsnummer erhöhen, wenn Sie wichtige Änderungen vornehmen: 

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

Dadurch wird sichergestellt, dass jeder die neue Datei erhält. Es funktioniert, weil der Browser die URL der Datei überprüft, um festzustellen, ob sich eine Kopie im Cache befindet. Wenn Ihr Server nicht so konfiguriert ist, dass er mit der Abfragezeichenfolge etwas anfängt, wird er ignoriert, aber der Name sieht im Browser wie eine neue Datei aus.

Wenn Sie dagegen 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, wäre es ein guter Trick, automatisch einen Abfragezeichenfolge-Parameter 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 Dateien im Cache gehalten werden. Browser haben Richtlinien für diese Art von Dingen, und sie spielen normalerweise nach den in der HTTP-Spezifikation festgelegten Regeln. 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 eine Anforderung für dieselbe Datei findet, erkennt er, dass er eine Kopie im Cache hat, und sucht nach dem EXPIRES-Datum, um zu entscheiden, ob sie 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 die Servereinstellungen anpassen und die EXPIRES-Header ändern, aber die oben beschriebene kleine Technik ist wahrscheinlich viel einfacher für Sie. Da die Zwischenspeicherung gut ist, möchten Sie dieses Datum normalerweise weit in die Zukunft festlegen (ein "Weit in die Zukunft ablaufender Header") und die oben beschriebene Technik verwenden, um eine Änderung zu erzwingen.

Wenn Sie mehr über HTTP erfahren möchten oder wissen möchten, wie diese Anforderungen gestellt werden, ist ein gutes Buch "High Performance Web Sites" von Steve Souders. Es ist eine sehr gute Einführung in das Thema.

176
keparo

Das mod_pagespeed plugin von Apache von Google führt für Sie die automatische Versionierung durch. Es ist wirklich glatt.

Es analysiert HTML auf seinem Weg aus dem Webserver (arbeitet mit PHP, Rails, Python, statischem HTML - irgendetwas) und schreibt Links zu CSS-, JS- und Image-Dateien so, dass sie einen ID-Code enthalten. Es bedient die Dateien an den geänderten URLs mit einer sehr langen Cache-Kontrolle. 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 außen minimieren.

111
Leopd

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

Ihre URL wäre also ungefähr so

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

Sie können immer noch die Umschreibungsregel verwenden, um den Hash zu entfernen. Der Vorteil besteht jedoch darin, dass Sie die Cache-Richtlinie jetzt auf "Für immer Cache" 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 in eine separate Datei verschieben, um es aufzunehmen).

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

90
levik

Nicht sicher, warum Sie sich bei der Implementierung dieser Lösung so viel Mühe geben.

Alles, was Sie tun müssen, wenn Sie den geänderten Zeitstempel der Datei erhalten und als Abfragestring an die Datei anhängen

In PHP würde ich Folgendes tun:

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

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

59
Phantom007

Sie können einfach ?foo=1234 am Ende Ihres css/js-Imports einfügen und 1234 so ändern, wie Sie möchten. Ein Beispiel finden Sie in der HTML-Quelle SO.

Die Idee, dass das? Parameter werden in der Anfrage trotzdem verworfen/ignoriert, und Sie können diese Anzahl ändern, wenn Sie eine neue Version einführen.


Hinweis: Es gibt einige Argumente in Bezug darauf, wie genau dies die Zwischenspeicherung beeinflusst. Ich glaube, dass der generelle Vorteil darin besteht, dass GET-Anforderungen mit oder ohne Parameter zwischengespeichert werden sollten, sodass die obige Lösung funktionieren sollte.

Es ist jedoch Sache des Webservers, zu entscheiden, ob er sich an diesen Teil der Spezifikation halten möchte, und den Browser, den der Benutzer verwendet, da er einfach weitermachen und trotzdem nach einer neuen Version fragen kann.

51
SCdF

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 einzufügen und sie mithilfe von Umschreibungshandlern oder URL-Konfessionen zu entfernen.

Siehe auch:

38
John Millikin

Die rund 30 vorhandenen Antworten sind ein guter Tipp für eine Website von circa 2008. Wenn es sich jedoch um eine moderne Single-Page-Anwendung (SPA) handelt, ist es möglicherweise an der Zeit, einige grundlegende Annahmen zu überdenken. Insbesondere die Vorstellung, dass der Webserver wünschenswert ist, nur den einen oder den einzigen Server zu bedienen neueste Version einer Datei.

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

  1. Ihre CD-Pipeline implementiert die neue Version N der Anwendung auf dem Server
  2. Sie navigieren innerhalb des SPA, der eine XHR an den Server sendet, um /some.template.__ zu erhalten.
    • (Ihr Browser hat die Seite nicht aktualisiert, daher wird noch Version M ausgeführt)
  3. Der Server antwortet mit dem Inhalt von /some.template - Soll die Version M oder N der Vorlage zurückgegeben werden?

Wenn das Format von /some.template zwischen den Versionen M und N geändert wurde (oder die Datei umbenannt wurde oder nicht) , möchten Sie wahrscheinlich keine Version N der Vorlage, die an den Browser gesendet wurde, der die alte Version M des Parsers ausführt. †

Web-Apps treten bei diesem Problem auf, wenn zwei Bedingungen erfüllt sind:

  • Ressourcen werden nach dem ersten Laden der Seite asynchron angefordert
  • Die App-Logik geht davon aus, dass sich der Inhalt der Ressource (was in zukünftigen Versionen geändert werden kann) ändert

Wenn Ihre App mehrere Versionen parallel bereitstellen muss, wird das -Löschen zwischengespeichert und "reloading" trivial:

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

Der letzte Schritt klingt schwierig, da für jeden URL in Ihrem serverseitigen oder clientseitigen Code ein URL-Builder aufgerufen werden muss. Oder Sie können einfach den Tag <base> verwenden 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. Damit alle laufenden Vorgänge abgeschlossen werden können, ist es dennoch am einfachsten, mindestens zwei Versionen parallel zu unterstützen: v-current und v-previous.

22
Michael Kropat

Verwenden Sie nicht foo.css? Version = 1! Browser sollen keine URLs mit GET-Variablen zwischenspeichern. Laut http://www.thinkvitamin.com/features/webapps/serving-javascript-fast , obwohl IE und Firefox dies ignorieren, Opera und Safari nicht! Verwenden Sie stattdessen foo.v1234.css und verwenden Sie Umschreiberegeln, um die Versionsnummer zu entfernen.

14
airrob

Für ASP.NET 4.5 und höher können Sie script bundling verwenden.

Die Anforderung http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81 ist für das Bundle AllMyScripts und enthält ein Abfragezeichenfolgepaar v = r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81. Die Abfragezeichenfolge v hat ein Wertetoken, bei dem es sich um eine eindeutige Kennung handelt, die für die Zwischenspeicherung 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, um sicherzustellen, dass die Browseranforderungen für das Bundle das neueste Bundle erhalten.

Die Bündelung bietet weitere Vorteile, einschließlich einer verbesserten Leistung beim erstmaligen Laden von Seiten mit Minification.

10
user3738893

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

Ich fügte eine Punktnegierungsklasse [^.] Zur Regex hinzu, also .number. wird ignoriert.

RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]
9
Nick Johnson

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);
    }

})();

Das Obige wird nach dem letzten Besuch Ihrer Website suchen. Wenn der letzte Besuch vor der Veröffentlichung des neuen Codes stattfand, verwendet location.reload(true) die Seitenaktualisierung vom Server. 

Normalerweise habe ich dies als erstes Skript im <head>, also wird es ausgewertet, bevor irgendein anderer Inhalt geladen wird. Wenn ein Nachladen erforderlich ist, ist dies für den Benutzer kaum wahrnehmbar.

Ich verwende lokalen Speicher, um den Zeitstempel des letzten Besuchs im Browser zu speichern. Sie können jedoch Cookies zum Mix hinzufügen, wenn Sie ältere Versionen von IE unterstützen möchten.

8
Lloyd Banks

Interessanter Beitrag. Nachdem ich alle Antworten hier zusammen mit der Tatsache gelesen hatte, dass ich noch nie Probleme mit "gefälschten" Abfragezeichenfolgen hatte (was ich nicht sicher bin, warum alle dies nur ungern verwenden), denke ich, dass die Lösung (die die Notwendigkeit des Umschreibens von Apache-Regeln aufhebt) wie in der akzeptierten Antwort) ist es, einen kurzen HASH des CSS-Dateiinhalts (anstelle der Datei datetime) als gefälschten Abfragestring zu berechnen.

Dies würde folgendes ergeben:

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

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

8
Michiel

In Laravel (PHP) können wir dies auf eine klare und elegante Art und Weise tun (unter Verwendung des Zeitstempels für die Dateiänderung):

<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'))}}">
8

Danke 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 ihn 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.

6
lony

Habe den clientseitigen DOM-Ansatz nicht gefunden und das Skriptknotenelement (oder das 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>
5
GreQ

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

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

Angenommen, Sie haben eine Datei unter:

/styles/screen.css

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

/styles/screen.css?v=1234

oder Sie können Versionsinformationen voranstellen, z. B .:

/v/1234/styles/screen.css

IMHO ist die zweite Methode für CSS-Dateien besser, da sie sich auf Bilder beziehen können, die relative URLs verwenden. Wenn Sie also einen background-image angeben, bedeutet dies:

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

seine URL wird effektiv sein:

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

Das heißt, wenn Sie die verwendete Versionsnummer aktualisieren, behandelt der Server diese als neue Ressource und verwendet keine zwischengespeicherte Version. Wenn Sie Ihre Versionsnummer auf Subversion/CVS/etc setzen. Revision bedeutet, dass Änderungen an Bildern, auf die in CSS-Dateien verwiesen wird, bemerkt werden. Dies ist beim ersten Schema nicht garantiert, d. H. Die URL images/happy.gif relativ zu /styles/screen.css?v=1235 ist /styles/images/happy.gif, die keine Versionsinformationen enthält.

Ich habe eine Cachelösung implementiert, die diese Technik mit Java-Servlets verwendet, und einfach Anforderungen an /v/* mit einem Servlet behandeln, das an die zugrunde liegende Ressource delegiert (d. H. /styles/screen.css). Im Entwicklungsmodus stelle ich Caching-Header ein, die den Client anweisen, die Aktualität der Ressource immer auf dem Server zu überprüfen (dies führt in der Regel zu einem Fehler, wenn Sie an Tomcats DefaultServlet delegieren und die Datei .css, .js usw.) nicht geändert wird Im Deployment-Modus setze ich Header, die "cache forever" sagen.

5
Walter Rumsby

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

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

Wenn Sie eine Versionsweite Zwischenspeicherung wünschen, können Sie Code zum Drucken des Dateidatums oder ähnlichem hinzufügen. Wenn Sie Java verwenden, können Sie einen benutzerdefinierten 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>
5
helios

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

Auf diese Weise eingeschlossene 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 wird in Global.asax auf folgende Weise 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();
    }
    ...
}
5
Ivan Kochurkin

google chrome verfügt über die Option Hard Reload sowie Empty Cache und Hard Reload . Sie können auf die Reload-Taste (Im Inspektionsmodus) klicken, um eine auszuwählen.

4
unknown123

Ich habe das kürzlich mit Python gelöst. Hier der Code (sollte leicht in andere Sprachen übernommen werden können):

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 die 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 Ihre HTML-Datei nie mehr ändern müssen. Wenn Sie die CSS-Datei berühren, wird automatisch eine Cache-Ungültigerklärung ausgelöst. Funktioniert sehr gut und der Aufwand fällt nicht auf.

4
pi.

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

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

Klicken Sie bei geöffneten Entwicklertools einfach auf die Aktualisierungsschaltfläche, und lassen Sie die Maustaste los, wenn Sie über "Leerer Cache und hartes Nachladen" fahren.

Dies ist mein bester Freund und ist eine superleichte Art, das zu bekommen, was Sie wollen!

4
Frank Bryce

Ich füge diese Antwort als SilverStripe http://www.silverstripe.org spezifische Antwort hinzu, nach der ich gesucht habe und die ich nie gefunden habe, die ich aber beim Lesen gefunden habe: http://api.silverstripe.org /3.0/source-class-SS_Datetime.html#98-110

Hoffentlich hilft dies jemandem, der eine SilverStripe-Vorlage verwendet und versucht, bei jedem Seitenbesuch/-aktualisierung ein zwischengespeichertes Bild zu laden. In meinem Fall handelt es sich um eine GIF-Animation, die nur einmal abgespielt wird und daher nicht wiedergegeben wurde, nachdem sie zwischengespeichert wurde. In meiner Vorlage habe ich einfach hinzugefügt:

?$Now.Format(dmYHis)

bis zum Ende des Dateipfads, um einen eindeutigen Zeitstempel zu erstellen und den Browser zu zwingen, ihn als neue Datei zu behandeln. 

2
pinkp

Tut mir leid, dass Sie einen toten Thread zurückgebracht haben. 

@ TomA ist richtig. 

Die Verwendung der "Querystring" -Methode wird nicht wie von Steve Souders unten angegeben zwischengespeichert:

... dass Squid, ein beliebter Proxy, keine Ressourcen mit einem .__-Cache zwischenspeichert. Querzeichenfolge.

@ TomA Vorschlag zur Verwendung von style.TIMESTAMP.css ist gut, aber MD5 wäre viel besser, da nur dann, wenn der Inhalt wirklich geändert wurde, auch der MD5 geändert wird.

2
Tai Li

Es scheint, dass alle Antworten hier eine Art Versionierung im Namensschema vorschlagen, das seine Schattenseiten hat.

Browser sollten wissen, was sie zwischenspeichern und was nicht zwischenspeichern soll, indem sie die Antwort des Webservers lesen, insbesondere die http-Header. Wurde diese Ressource seit dem letzten Abruf aktualisiert? und so weiter. 

Wenn die Dinge "richtig" konfiguriert sind, sollten durch das Aktualisieren der Dateien Ihrer Anwendung (irgendwann) die Browser-Caches aktualisiert werden. Sie können Ihren Webserver beispielsweise so konfigurieren, dass der Browser niemals Dateien zwischenspeichert (was eine schlechte Idee ist). 

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

2
commonpike

Ich habe einen MD5-Hash des Inhalts der Datei in die URL eingefügt. Auf diese Weise kann ich ein sehr langes Ablaufdatum festlegen und muss mich nicht um Benutzer mit alten JS oder CSS kümmern.

Ich berechne dies auch einmal pro Datei zur Laufzeit (oder bei Änderungen des Dateisystems), sodass zur Entwurfszeit oder während des Erstellungsprozesses nichts Lustiges zu tun ist.

Wenn Sie ASP.NET MVC verwenden, können Sie den Code in meiner anderen Antwort hier überprüfen.

2
Drew Noakes

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/[email protected](System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/css/custom.css")).ToString(),"[^0-9]", ""))" />

<script type="text/javascript" src="~/js/[email protected](System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/js/custom.js")).ToString(),"[^0-9]", ""))"></script>    
2
Luis Cambustón

Ich empfehle die Implementierung des folgenden Prozesses:

  • version Ihrer css/js-Dateien bei jeder Bereitstellung, z.

  • minimieren Sie sie, um Ladezeiten zu optimieren

2
Dan Burzo

Für eine Java Servlet-Umgebung können Sie die Bibliothek Jawr betrachten. Die Funktionsseite erläutert, wie mit dem Zwischenspeichern gearbeitet wird:

Jawr wird sein Bestes geben, um Ihre Kunden zu zwingen, die Ressourcen zu cachen. Wenn ein Browser fragt, ob eine Datei geändert wurde, wird ein 304-Header (nicht geändert) ohne Inhalt zurückgesendet. Andererseits sind Sie mit Jawr 100% sicher, dass neue Versionen Ihrer Bundles von allen Clients heruntergeladen werden. Jede URL zu Ihren Ressourcen enthält ein automatisch generiertes, inhaltsbasiertes Präfix, das sich bei jeder Aktualisierung automatisch ändert. Sobald Sie eine neue Version bereitstellen, ändert sich auch die URL für das Bundle, sodass ein Client keine ältere, zwischengespeicherte Version verwenden kann.

Die Bibliothek führt auch eine js/css-Minifizierung durch. Sie können sie jedoch deaktivieren, wenn Sie dies nicht möchten.

2
holmis83

Wenn Sie git + php verwenden, können Sie das Skript bei jeder Änderung des git-Repos erneut aus dem Cache laden, indem Sie folgenden Code verwenden:

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

Fügen Sie diesen Code einfach dort hinzu, wo Sie hart nachladen möchten (Browser zwingen, zwischengespeicherte CSS/JS-Dateien neu zu laden) Tun Sie dies innerhalb von .load, damit es nicht wie eine Schleife aktualisiert wird

 $( window ).load(function() {
   location.reload(true);
});
2
Karan Shaw

Wenn Sie einen modernen Browser verwenden, können Sie die Browser über eine Manifestdatei informieren, welche Dateien aktualisiert werden müssen. Dies erfordert keine Header, keine Versionen in URLs etc ...

Weitere Informationen finden Sie unter: Siehe: https://developer.mozilla.org/nl/docs/Web/HTML/Applicatie_cache_gebruiken#Introduction

2
Jos

Ich sehe ein Problem mit dem Ansatz der Verwendung eines Zeitstempel- oder Hash-basierten Differenzierungszeichens in der Ressourcen-URL, das bei Anforderung auf dem Server entfernt wird. Die Seite, die den Link zu z. das Stylesheet wird möglicherweise auch zwischengespeichert . Daher fordert die zwischengespeicherte Seite möglicherweise eine ältere Version des Stylesheets an, es wird jedoch die neueste Version bereitgestellt, die mit der anfordernden Seite möglicherweise nicht funktioniert.

Um dies zu beheben, müssen Sie entweder die anfragende Seite mit einem no-cache-Header oder einem Meta schützen, um sicherzustellen, dass sie bei jedem Laden aktualisiert wird. Oder Sie müssen alle Versionen der Style-Datei, die Sie jemals auf dem Server bereitgestellt haben, jeweils als einzelne Datei und mit ihrem Unterscheidungsmerkmal beibehalten, damit die anfragende Seite die Version der Style-Datei erhalten kann designed für. Im letzteren Fall verknüpfen Sie grundsätzlich die Versionen der HTML-Seite und des Stylesheets miteinander, was statisch erfolgen kann und keine Serverlogik erfordert.

1
ThomasH

"Eine andere Idee, die von SCdF vorgeschlagen wurde, wäre das Anhängen einer falschen Abfragezeichenfolge an die Datei. (Einige Python-Codes für die automatische Verwendung des Zeitstempels, da eine falsche Abfragezeichenfolge von pi übermittelt wurde.) Es gibt jedoch einige Diskussionen darüber, ob oder Der Browser würde eine Datei nicht mit einer Abfragezeichenfolge im Cache speichern (Denken Sie daran, dass der Browser die Datei zwischenspeichern und für zukünftige Besuche verwenden soll. Wir möchten, dass die Datei nur dann erneut abgerufen wird, wenn sie geändert wurde.) Da sie nicht eindeutig ist Was passiert mit einer falschen Abfragezeichenfolge, ich akzeptiere diese Antwort nicht. "

<link rel = "stylesheet" href = "file.css? <? = hash_hmac ('sha1', session_id (), md5_file (" file.css "));?>" />

Hashing der Datei bedeutet, dass sich die Abfragezeichenfolge geändert hat, wenn sie geändert wurde. Wenn nicht, bleibt es gleich. Jede Sitzung erzwingt auch ein Neuladen.

Optional können Sie auch Umschreibungen verwenden, um den Browser für einen neuen URI zu halten

1

Deaktivieren Sie den Cache von script.js nur für lokale Entwicklung in Pure JS

zufügt script.js? wizardry = 1231234 ein und blockiert reguläre script.js

<script type="text/javascript">
  if(document.location.href.indexOf('localhost') !== -1) {
    const scr = document.createElement('script');
    document.setAttribute('type', 'text/javascript');
    document.setAttribute('src', 'scripts.js' + '?wizardry=' + Math.random());
    document.head.appendChild(scr);
    document.write('<script type="application/x-suppress">'); // prevent next script(from other SO answer)
  }
</script>
<script type="text/javascript" src="scripts.js">
1
Pawel

Ein weiterer Vorschlag für ASP.Net-Websites

  1. Legen Sie eine andere Cache-Steuerung fest: Max-Age-Werte für verschiedene statische Dateien. 
  2. Bei css/js-Dateien ist die Wahrscheinlichkeit, dass diese Dateien auf dem Server geändert werden, groß. Setzen Sie daher eine minimale Cache-Kontrolle: Maximalwert von 1 oder 2 Minuten oder etwas, das Ihren Anforderungen entspricht. 
  3. Legen Sie für Bilder ein Ferndatum als Cache-Kontrolle fest: Maximalwert, beispielsweise 360 ​​Tage. 
  4. Auf diese Weise werden bei der ersten Anforderung alle statischen Inhalte mit einer 200-OK-Antwort auf den Clientcomputer heruntergeladen.
  5. Bei nachfolgenden Anfragen und nach zwei Minuten sehen wir 304-Not Modified-Anforderungen in css- und js-Dateien, wodurch die css/js-Versionierung vermieden wird.
  6. Bilddateien werden nicht angefordert, da sie aus dem zwischengespeicherten Speicher verwendet werden, bis der Cache abläuft.
  7. Durch die Verwendung der folgenden web.config-Konfigurationen erreichen wir das oben beschriebene Verhalten

Ich kam auf diese Frage, als ich nach einer Lösung für mein SPA suchte, das nur eine einzige index.html enthält, die alle erforderlichen Dateien auflistet. Während ich einige Hinweise bekam, die mir geholfen haben, konnte ich keine schnelle und einfache Lösung finden.

Am Ende habe ich eine kurze Seite (einschließlich des gesamten Codes) geschrieben, die erforderlich ist, um eine html/js index.html als Teil des Veröffentlichungsprozesses zu automatisieren. Es funktioniert perfekt und aktualisiert nur neue Dateien basierend auf dem Datum der letzten Änderung. 

Sie finden meinen Beitrag unter http://blueskycont.com/wp/2016/05/12/autoversion-your-spa-index-html/ . Es gibt auch eine frei funktionierende Winapp.

Der Kern des Codes ist

       private void ParseIndex(string inFile, string addPath, string outFile)
    {
        string path = Path.GetDirectoryName(inFile);
        HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
        document.Load(inFile);
        foreach (HtmlNode link in document.DocumentNode.Descendants("script"))
        {
            if (link.Attributes["src"]!=null)
            {
                resetQueryString(path, addPath, link, "src");
            }
        }
        foreach (HtmlNode link in document.DocumentNode.Descendants("link"))
        {
            if (link.Attributes["href"] != null && link.Attributes["type"] != null)
            {
                if (link.Attributes["type"].Value == "text/css" || link.Attributes["type"].Value == "text/html")
                {
                    resetQueryString(path, addPath, link, "href");
                }
            }
        }
        document.Save(outFile);
        MessageBox.Show("Your file has been processed.", "Autoversion complete");
    }

    private void resetQueryString(string path, string addPath, HtmlNode link, string attrType)
    {
        string currFileName = link.Attributes[attrType].Value;

        string uripath = currFileName;
        if (currFileName.Contains('?')) uripath = currFileName.Substring(0, currFileName.IndexOf('?'));
        string baseFile = Path.Combine(path, uripath);
        if (!File.Exists(baseFile)) baseFile = Path.Combine(addPath, uripath);
        if (!File.Exists(baseFile)) return;
        DateTime lastModified = System.IO.File.GetLastWriteTime(baseFile);
        link.Attributes[attrType].Value = uripath + "?v=" + lastModified.ToString("yyyyMMddhhmm");
    }
1
statler

Viele Antworten sprechen sich dafür aus, der URL einen Zeitstempel hinzuzufügen. Wenn Sie Ihre Produktionsdateien nicht direkt ändern, gibt der Zeitstempel der Datei wahrscheinlich nicht den Zeitpunkt an, zu dem eine Datei geändert wurde. In den meisten Fällen ändert sich die URL häufiger als die Datei selbst. Aus diesem Grund sollten Sie einen schnellen Hash des Dateiinhalts verwenden, z. B. MD5, wie von levik und anderen vorgeschlagen.

Beachten Sie, dass der Wert einmal beim Build oder beim Ausführen berechnet werden sollte und nicht bei jeder Anforderung der Datei.

Hier ein einfaches Bash-Skript, das eine Liste der Dateinamen von stdin liest und eine json-Datei mit Hashes in stdout schreibt:

#!/bin/bash
# create a json map from filenames to md5s
# run as hashes.sh < inputfile.list > outputfile.json

echo "{"
delim=""
while read l; do
    echo "$delim\"$l\": \"`md5 -q $l`\""
    delim=","
done
echo "}"

Diese Datei könnte dann beim Serverstart geladen und referenziert werden, anstatt das Dateisystem zu lesen.

1
undefined

Wenn Sie ein Entwickler sind, der das Zwischenspeichern vermeiden möchte, hat die Registerkarte chrome die Option zum Deaktivieren des Zwischenspeichers. Andernfalls können Sie mithilfe von zwei Skript-Tags auf ein Server-Rendering-Framework verzichten.

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

Eine der besten und schnellsten Methoden, die ich kenne, ist, den Namen des Ordners zu ändern, in dem Sie habe CSS- oder JS-Dateien . OR für Entwickler . Ändern Sie den Namen Ihrer CSS/js-Dateien, z. B. Versionen.

<link rel="stylesheet" href="cssfolder/somecssfile-ver-1.css"/>

Machen Sie dasselbe für Ihre Js-Dateien.

0
Bangash

Meine Methode, dies zu tun, besteht einfach darin, das Link-Element in eine serverseitige Seite aufzunehmen:

<!--#include virtual="/includes/css-element.txt"-->

wo der Inhalt von css-element.txt ist

<link rel="stylesheet" href="mycss.css"/>

an dem Tag, an dem Sie eine Verknüpfung zu my-new-css.css herstellen möchten, ändern Sie einfach das Include.

0
AmbroseChapel

Kleine Verbesserung von vorhandenen Antworten ...

Die Verwendung einer Zufallszahl oder einer Sitzungs-ID würde dazu führen, dass jede Anforderung erneut geladen wird. Im Idealfall müssen wir möglicherweise nur ändern, wenn in einer js/css-Datei Codeänderungen vorgenommen wurden. Wenn Sie eine gemeinsame JSP-Datei als Vorlage für viele andere JSP- und JS-Dateien verwenden Fügen Sie unten in einer allgemeinen JSP-Datei hinzu

<%@ taglib prefix="c" uri="http://Java.Sun.com/jsp/jstl/core"%>
<c:set var = "version" scope = "application" value = "1.0.0" />

Verwenden Sie nun die obige Variable an allen Speicherorten wie unten in Ihren js-Dateieinträgen.

<script src='<spring:url value="/js/myChangedFile.js?version=${version}"/>'></script>

Vorteile:

1) Dieser Ansatz hilft Ihnen, die Versionsnummer nur an einem Ort zu ändern.

2) Wenn Sie die richtige Versionsnummer (normalerweise Build-/Release-Nummer) beibehalten, können Sie überprüfen, ob die Codeänderungen ordnungsgemäß bereitgestellt wurden (von der Entwicklerkonsole des Browsers aus).

Noch ein nützlicher Tipp:

Wenn Sie den Chrome-Browser verwenden, können Sie die Zwischenspeicherung deaktivieren, wenn das Dev Tool geöffnet ist. In Chrome Hit F12> F1 blättern Sie zu Einstellungen> Voreinstellungen> Netzwerk> Zwischenspeicherung deaktivieren (während DevTools geöffnet ist)

 Chrome DevTools

0

Nun, ich habe es mir vorgenommen, indem ich die js-Version jedes Mal ändert, wenn die Seite geladen wird, indem eine zufällige Nummer zur js-Dateiversion hinzugefügt wird:

// Add it to the top of the page
<?php
srand();
$random_number = Rand();
?>

Wenden Sie dann die Zufallszahl wie folgt auf die js-Version an:

<script src="file.js?version=<?php echo $random_number;?>"></script>
0
Al3abMizo Games