web-dev-qa-db-fra.com

Meilleure façon d'empêcher la mise en cache des fichiers JavaScript par le navigateur

C'est ainsi que nous empêchons les navigateurs de mettre en cache les fichiers JS et CSS. Cela semble légèrement hacky .. y at-il une meilleure façon?

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

Mise à jour: la raison pour laquelle nous souhaitons empêcher la mise en cache est de nous assurer que la version la plus récente des fichiers est chargée lors de la création d'une nouvelle version.

21
Marcus Leon

Vous voulez que CSS et JS soient mis en cache. Cela accélère le chargement de la page Web quand ils reviennent. En ajoutant un horodatage, votre utilisateur sera obligé de le télécharger encore et encore.

Si vous voulez vous assurer qu'ils ont toujours une nouvelle version, demandez à votre système de construction d'ajouter un numéro de construction à la fin du fichier au lieu d'un horodatage.

Si vous rencontrez des problèmes avec Dev uniquement, assurez-vous de configurer vos navigateurs de manière à ne pas mettre en cache les fichiers ou que les en-têtes de vos pages de développement ne soient pas en cache.

22
epascarello

La mise en cache est votre ami. Si les navigateurs mettent ces fichiers en mémoire cache de manière incorrecte, cela signifie que les en-têtes HTTP envoyés par votre serveur Web sont erronés, ainsi que les fichiers JS et CSS eux-mêmes (et non la page HTML qui les utilise). Le navigateur utilise ces en-têtes pour déterminer s'il peut mettre le fichier en cache.

Votre serveur Web peut envoyer ces en-têtes (sur chaque fichier JS et CSS qu’il sert) pour indiquer aux navigateurs de ne pas les mettre en cache:

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

Mais cela augmentera la charge du réseau sur votre site et les utilisateurs verront la page se charger plus lentement. Vous pourriez être un peu plus indulgent et permettre au navigateur de mettre en cache le fichier CSS pendant 60 secondes:

Cache-Control: max-age=60

Si vous voulez vraiment que le navigateur recherche un nouveau fichier à chaque chargement de page, vous pouvez toujours enregistrer du trafic réseau à l'aide d'un ETag:

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

ETag est simplement un identifiant unique créé par votre serveur Web chaque fois que le fichier est modifié. La prochaine fois que le navigateur veut le fichier, il demande au serveur: "/js/pm.init.js a-t-il toujours l'ETag o2389r98ur0w3894tuq894?" et si oui, votre serveur dit simplement "oui". Ainsi, votre serveur n'aura plus à envoyer le fichier entier et l'utilisateur n'aura pas besoin d'attendre le chargement. Gagnant-gagnant.

Comment convaincre votre serveur Web de générer automatiquement des ETags dépend du serveur. Ce n'est généralement pas difficile.

J'ai déjà vu le hack que vous utilisez. Comme sur le Web, ce n’est pas beau ni particulièrement efficace, mais ça marche.

17
Jason Orendorff

Si Si nous voulons empêcher la mise en cache, nous voulons nous assurer que la version la plus récente des fichiers est chargée lors de la création d’une nouvelle version. , vous voulez que le nouveau js soit chargé quand THERE IS une NOUVELLE version, pas toutes les fois. 

Pour ce faire, vous souhaitez que la valeur "ts" soit liée au fichier et non à l'heure du jour. Vous pouvez utiliser l’un des systèmes suivants:

  1. ts = horodatage du fichier
  2. ts = MD5 (ou quelle que soit la somme de contrôle) du fichier
  3. ts = version du code. Si vous avez un script qui effectue le déploiement, assurez-vous qu'il ajoute le code de version (ou la date de publication) dans un fichier include qui sera affecté à ts.

De cette façon, le navigateur ne rechargera le fichier que s'il est nouveau et pas toutes les fois.

11
Chris Cinelli

Une approche simple consiste à utiliser la dernière date de modification des fichiers js ou css dans l’URL au lieu d’un horodatage. Cela aurait pour effet d'empêcher la mise en cache uniquement lorsqu'il existe une nouvelle version du fichier sur le serveur. 

3
user2784850

Modifier

Si vous utilisez Spring Boot, il est maintenant beaucoup plus simple d’empêcher la mise en cache des fichiers modifiés.

Tout ce que vous avez à faire est d’ajouter ceci à application.properties:

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

Si vous utilisez Thymeleaf ou FreeMarker, sa configuration est entièrement automatique. Si vous utilisez des fichiers JSP, vous devez déclarer manuellement un ResourceUrlEncodingFilter.

Lisez plus ici: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc -static-content

Ce qui suit est maintenant mon "ancien" post qui fonctionne aussi mais demande plus de travail.


Puisque vous utilisez Java, vous pouvez également utiliser maven pour gérer votre projet.

Dans ce cas, pour améliorer les performances et éviter qu'aucun navigateur ne mette en cache vos ressources statiques lorsqu'une nouvelle version de votre logiciel est produite, vous devez associer toutes vos feuilles de style et vos fichiers JavaScript à un seul fichier de ce type. faites en sorte que les URL de vos ressources changent lorsque vous créez une nouvelle version.

Heureusement, Maven peut faire tout cela pour vous au moment de la construction. Vous aurez besoin de minify-maven-plugin et maven-replacer-plugin.

Cet extrait d'un fichier pom.xml devrait vous aider à démarrer:

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

Voici comment inclure vos ressources statiques dans header.jsp

<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

À des fins de débogage, installez la barre d'outils pour développeur Web pour FireFox et activez-y "désactiver le cache"

Mettre à jour:
Lorsque FireBug est installé, vous pouvez désactiver la mise en cache également dans les paramètres de l'onglet Réseau .

1
powtac

Si vous pouvez inclure le filtre Java Servlet dans votre application, voici une solution qui fonctionne: CorrectBrowserCacheHandlerFilter.Java

Fondamentalement, lorsque votre navigateur demande les fichiers statiques, le serveur redirige toutes les demandes vers le même, mais avec un paramètre de requête de hachage (?v=azErT par exemple), qui dépend du contenu du fichier statique cible.

Ainsi, le navigateur ne mettra jamais en cache les fichiers statiques déclarés dans votre index.html par exemple (car recevra toujours un 302 Moved Temporarily), mais mettra uniquement en cache ceux avec la version de hachage (le serveur répondra 200 pour eux). Ainsi, le cache du navigateur sera utilisé efficacement pour les fichiers statiques avec une version de hachage.

Disclaimer: Je suis l'auteur de CorrectBrowserCacheHandlerFilter.Java.

0
Anthony O.