webentwicklung-frage-antwort-db.com.de

Besserer Weg, um das Browser-Caching von JavaScript-Dateien zu verhindern

So verhindern wir das Zwischenspeichern von JS- und CSS-Dateien durch Browser. Dies scheint ein bisschen hackig zu sein. Gibt es einen besseren Weg?

<%
//JSP code
long ts = (new Date()).getTime(); //Used to prevent JS/CSS caching
%>

<link rel="stylesheet" type="text/css" media="screen" href="/css/management.css?<%=ts %>" />
<script type="text/javascript" src="/js/pm.init.js?<%=ts %>"></script> 
<script type="text/javascript" src="/js/pm.util.func.js?<%=ts %>"></script> 

Update: Der Grund, warum wir das Cachen verhindern möchten, ist sicherzustellen, dass die neuere Version der Dateien geladen wird, wenn wir eine neue Version erstellen.

21
Marcus Leon

Sie möchten, dass CSS und JS zwischengespeichert werden. Es beschleunigt das Laden der Webseite, wenn diese zurückkommen. Durch das Hinzufügen eines Zeitstempels muss Ihr Benutzer ihn immer und immer wieder herunterladen.

Wenn Sie sicherstellen möchten, dass sie immer über eine neue Version verfügen, muss Ihr Build-System anstelle eines Zeitstempels eine Build-Nummer am Ende der Datei hinzufügen.

Wenn Sie nur in dev Probleme damit haben, stellen Sie sicher, dass Ihre Browser so eingerichtet sind, dass sie keine Dateien zwischenspeichern oder Header auf Ihren Dev-Seiten so einstellen, dass sie nicht im Cache sind.

22
epascarello

Caching ist dein Freund. Wenn Browser diese Dateien falsch zwischenspeichern, bedeutet dies, dass mit den HTTP-Headern, die Ihr Webserver zusammen mit den JS- und CSS-Dateien sendet, etwas nicht stimmt (nicht die HTML-Seite, die sie verwendet). Der Browser verwendet diese Header, um herauszufinden, ob er die Datei zwischenspeichern kann.

Ihr Webserver kann diese Header senden (in jeder JS- und CSS-Datei, die er bedient), um Browser anzuweisen, sie nicht im Cache zu speichern:

Cache-Control: no-cache
Pragma: no-cache
Expires: Sat, 01 Jan 2000 00:00:00 GMT

Dies erhöht jedoch die Netzwerklast auf Ihrer Site, und Benutzer werden die Seitenlast langsamer sehen. Sie könnten ein wenig nachsichtig sein und dem Browser erlauben, die CSS-Datei für 60 Sekunden zwischenzuspeichern:

Cache-Control: max-age=60

Wenn Sie wirklich möchten, dass der Browser bei jeder einzelnen Seite nach einer neuen Datei sucht, können Sie noch etwas Netzwerkverkehr mit einem ETag speichern:

Cache-Control: max-age=0
Pragma: no-cache
Expires: Sat, 01 Jan 2000 00:00:00 GMT
ETag: "o2389r-98ur0-w3894tu-q894"

Das ETag ist einfach eine eindeutige Kennung, die Ihr Webserver bei jeder Änderung der Datei vornimmt. Wenn der Browser die Datei das nächste Mal wünscht, fragt er den Server: "Hat /js/pm.init.js noch den ETag o2389r98ur0w3894tuq894?" und wenn ja, sagt Ihr Server einfach "Ja". Auf diese Weise muss der Server die gesamte Datei nicht erneut senden, und der Benutzer muss nicht warten, bis die Datei geladen ist. Win-Win.

Wie Sie Ihren Webserver davon überzeugen, ETags automatisch zu generieren, hängt vom Server ab. Es ist normalerweise nicht schwer.

Ich habe den Hack, den du benutzt hast, schon gesehen. Wie so viele im Web ist es nicht schön oder besonders effizient, aber es funktioniert.

17
Jason Orendorff

Wenn Der Zwischenspeicher soll verhindert werden, wenn die neue Version der Dateien geladen wird, wenn wir eine neue Version erstellen. , Sie möchten, dass das neue js geladen wird, wenn THERE IS eine NEUE Version ist, nicht immer. 

Zu diesem Zweck möchten Sie, dass der Wert "ts" mit der Datei und nicht mit der Tageszeit verknüpft ist. Sie können entweder eines dieser Systeme verwenden:

  1. ts = Zeitstempel der Datei
  2. ts = MD5 (oder eine andere Prüfsumme) der Datei
  3. ts = Version des Codes. Wenn Sie über ein Skript verfügen, das die Bereitstellung durchführt, müssen Sie sicherstellen, dass der Versionscode (oder das Datum der Veröffentlichung) in einer Include-Datei hinzugefügt wird, die ts zugewiesen wird.

Auf diese Weise lädt der Browser die Datei nur dann neu, wenn sie neu ist und nicht alle Zeiten.

11
Chris Cinelli

Ein einfacher Ansatz wäre, das Datum der letzten Änderung der js- oder css-Dateien in der URL anstelle eines Zeitstempels zu verwenden. Dies hat den Effekt, dass das Zwischenspeichern nur verhindert wird, wenn eine neue Version der Datei auf dem Server vorhanden ist. 

3
user2784850

Bearbeiten

Falls Sie Spring Boot verwenden, ist es jetzt viel einfacher, das Zwischenspeichern geänderter Dateien zu verhindern.

Alles was Sie tun müssen, ist dies zu application.properties hinzuzufügen:

spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

Wenn Sie Thymeleaf oder FreeMarker verwenden, ist es vollständig automatisch konfiguriert. Wenn Sie JSPs verwenden, müssen Sie einen ResourceUrlEncodingFilter manuell deklarieren.

Lesen Sie hier mehr: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc -statischer-Inhalt

Was jetzt folgt, ist mein "alter" Beitrag, der zwar funktioniert, aber mehr Arbeit erfordert.


Da Sie Java verwenden, besteht die Möglichkeit, dass Sie auch mit Maven Ihr Projekt verwalten.

In diesem Fall sollten Sie, um die Leistung zu verbessern und sicherzustellen, dass kein Browser Ihre statischen Ressourcen zwischenspeichert, wenn eine neue Version Ihrer Software erstellt wird, alle Stylesheets und JavaScript-Dateien in einer einzigen Datei ihres Typs zusammenfassen Ändern Sie die Ressourcen-URLs, wenn Sie eine neue Version erstellen.

Glücklicherweise kann maven das alles zur Bauzeit für Sie erledigen. Sie benötigen minify-maven-plugin und maven-replacer-plugin.

Dieser Auszug einer pom.xml sollte Ihnen den Einstieg erleichtern:

<properties>
    <timestamp>${maven.build.timestamp}</timestamp>
    <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
</properties>

<plugin>
    <groupId>com.samaxes.maven</groupId>
    <artifactId>minify-maven-plugin</artifactId>
    <version>1.6</version>
    <executions>
        <execution>
            <id>minify-css</id>
            <phase>process-resources</phase>
            <goals>
                <goal>minify</goal>
            </goals>
            <configuration>
                <linebreak>-1</linebreak>
                <cssSourceDir>resources/css</cssSourceDir>
                <cssSourceFiles>
                    <cssSourceFile>bootstrap.css</cssSourceFile>
                    <cssSourceFile>style.css</cssSourceFile>
                </cssSourceFiles>
                <cssTargetDir>resources/css</cssTargetDir>
                <cssFinalFile>${timestamp}.css</cssFinalFile>
            </configuration>
        </execution>
        <execution>
            <id>minify-js</id>
            <phase>process-resources</phase>
            <goals>
                <goal>minify</goal>
            </goals>
            <configuration>
                <linebreak>-1</linebreak>
                <jsSourceDir>resources/js</jsSourceDir>
                <jsSourceFiles>
                    <jsSourceFile>jquery.js</jsSourceFile>
                    <jsSourceFile>bootstrap.js</jsSourceFile>
                    <jsSourceFile>script.js</jsSourceFile>
                </jsSourceFiles>
                <jsTargetDir>resources/js</jsTargetDir>
                <jsFinalFile>${timestamp}.js</jsFinalFile>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>com.google.code.maven-replacer-plugin</groupId>
    <artifactId>replacer</artifactId>
    <version>1.5.2</version>
    <executions>
        <execution>
            <id>replaceDynPartInResourcePath</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>replace</goal>
            </goals>
            <configuration>
                <ignoreMissingFile>false</ignoreMissingFile>
                <basedir>${project.build.directory}</basedir>
                <file>${project.artifactId}/WEB-INF/views/header.jsp</file>
                <regex>false</regex>
                <replacements>
                    <replacement>
                        <token>$dynamicResourceNamePart$</token>
                        <value>${timestamp}</value>
                    </replacement>
                </replacements>
            </configuration>
        </execution>
    </executions>
</plugin>

So fügen Sie Ihre statischen Ressourcen in header.jsp ein

<c:choose>
    <c:when test="${not fn:contains(pageContext.request.serverName, 'localhost') and empty param.nocombine}">
        <link href="${pageContext.request.contextPath}/resources/css/$dynamicResourceNamePart$.min.css" rel="stylesheet" type="text/css" />
        <script src="${pageContext.request.contextPath}/resources/js/$dynamicResourceNamePart$.min.js" type="text/javascript"></script>
    </c:when>
    <c:otherwise>
        <link href="${pageContext.request.contextPath}/resources/css/bootstrap.css" rel="stylesheet">
        <link href="${pageContext.request.contextPath}/resources/css/style.css" rel="stylesheet">
        <script type="text/javascript" src="${pageContext.request.contextPath}/resources/js/jquery.js"></script>
        <script type="text/javascript" src="${pageContext.request.contextPath}/resources/js/bootstrap.js"></script>
        <script type="text/javascript" src="${pageContext.request.contextPath}/resources/js/script.js"></script>
    </c:otherwise>
</c:choose>
3
yglodt

Für Debug-Zwecke installieren Sie die web developer toolbar for FireFox und aktivieren dort "Cache deaktivieren".

Update:
Wenn Sie FireBug installiert haben, können Sie das Zwischenspeichern auch in den Einstellungen auf der Registerkarte "Netzwerk" deaktivieren.

1
powtac

Wenn Sie Java-Servlet-Filter in Ihre Anwendung aufnehmen können, finden Sie hier eine funktionierende Lösung: CorrectBrowserCacheHandlerFilter.Java

Wenn Ihr Browser die statischen Dateien anfordert, leitet der Server grundsätzlich alle Anfragen an dieselbe um, jedoch mit einem Hash-Abfrageparameter (zum Beispiel ?v=azErT), der vom Inhalt der statischen Zieldatei abhängt.

In diesem Fall speichert der Browser niemals die in Ihrem index.html deklarierten statischen Dateien (weil er immer einen 302 Moved Temporarily erhalten hat), sondern nur die mit der Hash-Version (der Server antwortet 200). Daher wird der Browser-Cache effizient für statische Dateien mit Hash-Version verwendet.

Haftungsausschluss: Ich bin der Autor von CorrectBrowserCacheHandlerFilter.Java.

0
Anthony O.