Comment forcer le navigateur à recharger les fichiers cachés CSS / JS?

J'ai remarqué que certains navigateurs (en particulier, Firefox et Opera) sont très zélés pour utiliser des copies mises en cache de fichiers .css et .js , même entre les sessions du navigateur. Cela entraîne un problème lorsque vous mettez à jour un de ces fichiers, mais le navigateur de l'utilisateur continue d'utiliser la copie en cache.

La question est: quelle est la façon la plus élégante de forcer le navigateur de l'utilisateur à recharger le fichier lorsqu'il a changé?

Idéalement, la solution ne forcerait pas le navigateur à recharger le fichier à chaque visite de la page. Je publierai ma propre solution en réponse, mais je suis curieux si quelqu'un a une meilleure solution et je vais laisser vos votes décider.

Mettre à jour:

Après avoir permis la discussion ici pendant un certain temps, j'ai trouvé John Millikin et la suggestion de Da5id utiles. Il s'avère qu'il y a un terme pour cela: version automatique .

J'ai posté une nouvelle réponse ci-dessous, qui est une combinaison de ma solution originale et de la suggestion de John.

Une autre idée suggérée par SCdF serait d'ajouter une chaîne de requête fausse au fichier. (Certains codes Python pour utiliser automatiquement l'horodatage comme une chaîne de requête fausse ont été soumis par pi .). Cependant, il y a une discussion sur le point de savoir si le navigateur mettrait en cache un fichier avec une chaîne de requête. (Rappelez-vous, nous voulons que le navigateur mette en cache le fichier et l'utilise dans les prochaines visites. Nous voulons seulement qu'il récupère le fichier lorsqu'il a changé.)

Comme il n'est pas clair ce qui se passe avec une chaîne de requête fausse, je n'accepte pas cette réponse.

    Mise à jour: Réécrit pour intégrer les suggestions de John Millikin et da5id . Cette solution est écrite en PHP, mais devrait être facilement adaptée à d'autres langues.

    Mise à jour 2: Intégrant les commentaires de Nick Johnson selon lesquels l'original .htaccess regex peut causer des problèmes avec les fichiers tels que json-1.3.js . La solution consiste uniquement à réécrire s'il y a exactement 10 chiffres à la fin. (Étant donné que 10 chiffres couvrent tous les horodateurs du 9/9/2001 au 20/11/2286).

    Tout d'abord, nous utilisons la règle de réécriture suivante dans .htaccess:

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

    Maintenant, nous écrivons la fonction PHP suivante:

     /** * Given a file, ie /css/base.css, replaces it with a string containing the * file's mtime, ie /css/base.1221534296.css. * * @param $file The file to be loaded. Must be an absolute path (ie * 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); } 

    Maintenant, chaque fois que vous incluez votre CSS, changez-le de ceci:

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

    Pour ça:

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

    De cette façon, vous ne devez jamais modifier à nouveau le lien, et l'utilisateur verra toujours le dernier CSS. Le navigateur pourra mettre en cache le fichier CSS, mais lorsque vous modifiez votre CSS, le navigateur affichera ceci comme une nouvelle URL, donc il n'utilisera pas la copie mise en cache.

    Cela peut également fonctionner avec des images, des favicons et JavaScript. Fondamentalement, tout ce qui n'est pas généré dynamiquement.

    Technique simple côté client

    En général, la mise en cache est bonne … Donc, il existe quelques techniques, selon que vous résolvez le problème lorsque vous développez un site Web, ou si vous essayez de contrôler le cache dans un environnement de production.

    Les visiteurs généraux de votre site Web n'auront pas la même expérience que vous avez lorsque vous développez le site. Étant donné que le visiteur moyen arrive moins souvent sur le site (peut-être que quelques fois par mois, sauf si vous êtes Google ou hi5 Networks), ils sont moins susceptibles d'avoir vos fichiers dans le cache, et cela peut suffire. Si vous souhaitez forcer une nouvelle version dans le navigateur, vous pouvez toujours ajouter une chaîne de requête à la requête, et afficher le numéro de version lorsque vous effectuez des modifications majeures:

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

    Cela garantira que tout le monde obtient le nouveau fichier. Cela fonctionne car le navigateur se penche sur l'URL du fichier pour déterminer s'il a une copie dans le cache. Si votre serveur n'est pas configuré pour faire quoi que ce soit avec la chaîne de requête, il sera ignoré, mais le nom ressemblera à un nouveau fichier sur le navigateur.

    D'autre part, si vous développez un site Web, vous ne souhaitez pas modifier le numéro de version chaque fois que vous enregistrez une modification de votre version de développement. Ce serait ennuyant.

    Donc, alors que vous développez votre site, un bon tour serait de générer automatiquement un paramètre de chaîne de requête:

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

    L'ajout d'une chaîne de requête à la demande est un bon moyen de la version d'une ressource, mais pour un site Web simple, cela peut être inutile. Et rappelez-vous, la mise en cache est une bonne chose.

    Il est également intéressant de noter que le navigateur n'est pas nécessairement avare de garder les fichiers dans le cache. Les navigateurs ont des politiques pour ce genre de chose, et ils fonctionnent généralement selon les règles établies dans la spécification HTTP. Lorsqu'un navigateur fait une demande à un serveur, une partie de la réponse est un en-tête EXPIRES … une date qui indique au navigateur combien de temps il doit être conservé dans le cache. La prochaine fois que le navigateur trouvera une requête pour le même fichier, il voit qu'il a une copie dans le cache et qu'il recherche la date EXPIRES pour décider s'il faut l'utiliser.

    Alors croyez-le ou non, c'est en fait votre serveur qui rend ce cache de navigateur tellement persistant. Vous pouvez ajuster les paramètres de votre serveur et changer les en-têtes EXPIRES, mais la petite technique que j'ai écrite ci-dessus est probablement une façon beaucoup plus simple d'y parvenir. Étant donné que la mise en cache est bonne, vous souhaitez généralement fixer cette date dans le futur (un «avenir lointain») et utiliser la technique décrite ci-dessus pour forcer une modification.

    Si vous êtes intéressé par plus d'informations sur HTTP ou comment ces demandes sont faites, un bon livre est "Sites Web haute performance" par Steve Souders. C'est une très bonne introduction au sujet.

    Le plugin mod_pagespeed de Google pour apache vous effectuera automatiquement la version. C'est vraiment très léger.

    Il analyse le HTML en sortant du serveur web (fonctionne avec PHP, rails, python, HTML statique – tout) et réécrit les liens vers CSS, JS, les fichiers image afin qu'ils incluent un code d'identification. Il sert les fichiers aux URL modifiées avec un contrôle de cache très long sur eux. Lorsque les fichiers changent, ils changent automatiquement les URL afin que le navigateur les récupère à nouveau. Il fonctionne fondamentalement, sans aucune modification de votre code. Il va même minimiser votre code en sortant aussi.

    Au lieu de changer la version manuellement, je vous recommande d'utiliser un hachage MD5 du fichier CSS réel.

    Donc, votre URL serait quelque chose comme

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

    Vous pouvez toujours utiliser la règle de réécriture pour éliminer le hash, mais l'avantage est maintenant que vous pouvez configurer votre stratégie de cache pour "cache pour toujours", car si l'URL est identique, cela signifie que le fichier est inchangé.

    Vous pouvez alors écrire un script shell simple qui calculerait le hash du fichier et mettrait à jour votre balise (vous voudrez probablement le déplacer vers un fichier séparé pour inclusion).

    Il suffit d'exécuter ce script chaque fois que CSS change et vous êtes bon. Le navigateur recharge SEULEMENT vos fichiers lorsqu'ils sont modifiés. Si vous faites une modification et que vous l'annulez, il n'y a aucune difficulté à déterminer la version à laquelle vous devez revenir pour que vos visiteurs ne puissent pas être téléchargés à nouveau.

    Vous pouvez simplement mettre ?foo=1234 à la fin de votre importation css / js, en changeant 1234 pour être ce que vous voulez. Jetez un oeil à la source SO html pour un exemple.

    L'idée qu'il y avait que le? Les paramètres sont ignorés / ignorés sur la demande de toute façon et vous pouvez modifier ce numéro lorsque vous déployez une nouvelle version.


    Remarque: Il existe un argument concernant exactement comment cela affecte la mise en cache. Je crois que l'essentiel est que les requêtes GET, avec ou sans paramètres devraient être cachable, donc la solution ci-dessus devrait fonctionner.

    Cependant, il appartient au serveur Web de décider s'il veut adhérer à cette partie de la spécification et au navigateur utilisé par l'utilisateur, car il peut aller tout de suite et demander une nouvelle version de toute façon.

    Je ne sais pas pourquoi vous êtes en train de prendre tant de peine à mettre en œuvre cette solution.

    Tout ce que vous devez faire si vous obtenez l'horodatage modifié du fichier et l'ajouter comme une requête sur le fichier

    En PHP, je le ferais comme suit:

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

    Filemtime est une fonction PHP qui renvoie l'horodatage modifié du fichier.

    J'ai entendu cela appeler "version automatique". La méthode la plus courante est d'inclure le mtime du fichier statique quelque part dans l'URL et de le supprimer en utilisant les gestionnaires de réécriture ou les URL confs:

    Voir également:

    • Version automatique de l'actif dans Django
    • Version automatique de vos fichiers CSS et JavaScript

    N'utilisez pas foo.css? Version = 1! Les navigateurs ne sont pas censés mettre en cache des URL avec des variables GET. Selon http://www.thinkvitamin.com/features/webapps/serving-javascript-fast , bien que IE et Firefox ignorent cela, Opera et Safari ne le font pas! Au lieu de cela, utilisez foo.v1234.css et utilisez des règles de réécriture pour éliminer le numéro de version.

    Les 30 réponses existantes sont d'excellents conseils pour un site web de circa 2008. Toutefois, en ce qui concerne une application de page unique (SPA) moderne, il pourrait être temps de réfléchir à certaines hypothèses fondamentales … spécifiquement l'idée qu'il est souhaitable que le serveur Web ne serve que la seule et la plus récente version d'un fichier.

    Imaginez que vous êtes un utilisateur qui a la version M d'un SPA chargé dans votre navigateur:

    1. Votre pipette CD déploie la nouvelle version N de l'application sur le serveur
    2. Vous naviguez dans le SPA, qui envoie un XHR au serveur pour obtenir /some.template
      • (Votre navigateur n'a pas actualisé la page, donc vous exécutez toujours la version M )
    3. Le serveur répond avec le contenu de /some.template – voulez-vous qu'il renvoie la version M ou N du modèle?

    Si le format de /some.template changé entre les versions M et N (ou le fichier a été renommé ou non), vous ne souhaitez probablement pas que la version N du modèle soit envoyée au navigateur qui exécute l'ancienne version M de l'analyseur . †

    Les applications Web se heurtent à ce problème lorsque deux conditions sont remplies:

    • Les ressources sont demandées de manière asynchrone après le chargement initial de la page
    • La logique de l'application suppose des choses (qui peuvent changer dans les versions futures) sur le contenu des ressources

    Une fois que votre application doit diffuser plusieurs versions en parallèle, résoudre la mise en cache et le "rechargement" devient trivial:

    1. Installez tous les fichiers de site dans les fichiers versionnés: /v<release_tag_1>/…files… , /v<release_tag_2>/…files…
    2. Définissez les en-têtes HTTP pour permettre aux navigateurs de cacher des fichiers pour toujours
      • (Ou mieux encore, mettre tout dans un CDN)
    3. Mettre à jour toutes les balises <script> et <link> , etc. pour pointer vers ce fichier dans l'un des dors de version

    Cette dernière étape semble délicate, car il pourrait être nécessaire d'appeler un générateur d'URL pour chaque URL de votre code côté serveur ou côté client. Ou vous pouvez simplement utiliser l' étiquette <base> et changer la version actuelle en un seul endroit.

    † Une façon de procéder est d'être agressif à propos du forçage du navigateur à recharger tout lors de la sortie d'une nouvelle version. Mais dans le but de laisser les opérations en cours se terminer, il est encore plus facile de supporter au moins deux versions en parallèle: v-current et v-previous.

    Le RewriteRule nécessite une petite mise à jour pour les fichiers js ou css qui contiennent un version de notation par points à la fin. Par exemple, json-1.3.js.

    J'ai ajouté une classe de négation de points [^.] Au regex ainsi .number. Est ignoré.

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

    Poste intéressant. Après avoir lu toutes les réponses ici, combiné au fait que je n'ai jamais eu de problèmes avec les chaînes de requêtes "fausses" (ce qui ne me doute pas pourquoi tout le monde est si réticent à l'utiliser) Je suppose que la solution (qui supprime le besoin de règles de réécriture d'apache Comme dans la réponse acceptée) est de calculer un HASH court du contenu du fichier CSS (au lieu de la date-date du fichier) comme une chaîne de requête fausse.

    Cela entraînerait ce qui suit:

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

    Bien sûr, les solutions de datetime ont également fait l'objet d'un fichier CSS, mais je pense qu'il s'agit du contenu du fichier css et non de la date-date du fichier, alors pourquoi les mélanger?

    Pour ASP.NET 4.5 et supérieur, vous pouvez utiliser le regroupement de scripts .

    La requête http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81 est pour le bundle AllMyScripts et contient une paire de chaînes de requêtes v = r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81. La chaîne de requête v a un jeton de valeur qui est un identifiant unique utilisé pour la mise en cache. Tant que le bundle ne change pas, l'application ASP.NET demandera le lot AllMyScripts à l'aide de ce jeton. Si un fichier dans le module change, le framework d'optimisation ASP.NET générera un nouveau jeton, garantissant que les requêtes du navigateur pour le bundle obtiendront le dernier paquet.

    Il existe d'autres avantages pour le regroupement, y compris une performance accrue sur les charges de la première page avec les minifications.

    Vous pouvez forcer une "mise en cache de la session" si vous ajoutez l'identifiant de session comme un paramètre spureous du fichier js / css:

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

    Si vous voulez une mise en cache de toute la version, vous pouvez ajouter un code pour imprimer la date du fichier ou similaire. Si vous utilisez Java, vous pouvez utiliser une balise personnalisée pour générer le lien de manière élégante.

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

    Disons que vous avez un fichier disponible à:

     /styles/screen.css 

    Vous pouvez soit ajouter un paramètre de requête avec des informations de version sur l'URI, par exemple:

     /styles/screen.css?v=1234 

    Ou vous pouvez préciser les informations de version, par exemple:

     /v/1234/styles/screen.css 

    IMHO, la deuxième méthode est meilleure pour les fichiers CSS, car ils peuvent se référer à des images à l'aide d'URL relatives, ce qui signifie que si vous spécifiez une background-image comme ceci:

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

    Son URL sera effectivement:

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

    Cela signifie que si vous mettez à jour le numéro de version utilisé, le serveur traitera ceci comme une nouvelle ressource et n'utilisera pas une version mise en cache. Si vous basez votre numéro de version sur Subversion / CVS / etc. La révision signifie que les modifications apportées aux images référencées dans les fichiers CSS seront remarquées. Cela n'est pas garanti avec le premier schéma, c'est-à-dire que les images/happy.gif URL images/happy.gif relatives à /styles/screen.css?v=1235 sont /styles/images/happy.gif qui ne contiennent aucune information de version.

    J'ai mis en place une solution de mise en cache en utilisant cette technique avec des servlets Java et simplement gérer des requêtes vers /v/* avec une servlet qui délègue à la ressource sous-jacente (c'est-à-dire /styles/screen.css ). En mode développement, je configure les en-têtes de mise en cache qui indiquent au client de vérifier toujours la fraîcheur de la ressource avec le serveur (cela entraîne généralement un 304 si vous délèguez à Defaultcat de Tomcat et que le fichier .css , .js , etc. n'a pas changé ) En mode de déploiement, j'ai configuré des en-têtes qui disent "cache pour toujours".

    Merci à Kip pour sa solution parfaite!

    Je l'ai étendu pour l'utiliser comme Zend_view_Helper. Parce que mon client a exécuté sa page sur un hôte virtuel, je l'ai également étendu pour cela.

    J'espère que cela aide quelqu'un d'autre aussi.

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

    Merci et merci.

    Voici une solution JavaScript pure

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

    Ce qui précède recherchera la dernière fois que l'utilisateur a visité votre site. Si la dernière visite était avant que vous ayez publié un nouveau code, il utilise location.reload(true) pour forcer la mise à jour de la page du serveur.

    J'ai généralement ce premier script dans le <head> afin qu'il soit évalué avant tout autre chargement de contenu. Si une recharge doit se produire, il est à peine perceptible pour l'utilisateur.

    J'utilise la mémoire locale pour stocker le dernier horodatage de la visite sur le navigateur, mais vous pouvez ajouter des cookies au mix si vous cherchez à prendre en charge les anciennes versions d'IE.

    J'ai récemment résolu cela en utilisant Python. Ici, le code (devrait être facile à adopter dans d'autres langues):

     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) 

    Ce code ajoute essentiellement l'horodatage des fichiers en tant que paramètre de requête à l'URL. L'appel de la fonction suivante

     script("/main.css") 

    aura pour résultat

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

    L'avantage, bien sûr, est que vous ne devez jamais modifier votre html à nouveau, le fait de toucher le fichier CSS déclenchera automatiquement une invalidation de cache. Fonctionne très bien et les frais généraux ne sont pas perceptibles.

    Vous pouvez simplement ajouter un nombre aléatoire avec l'URL CSS / JS comme

     example.css?randomNo=Math.random() 

    Pour ASP.NET je suppose la prochaine solution avec des options avancées (mode débogage / libération, versions):

    Js ou fichiers Css inclus de cette façon:

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

    Global.JsPostfix et Global.CssPostfix sont calculés de la manière suivante dans Global.asax:

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

    Je suggère de mettre en œuvre le processus suivant:

    • Versionz vos fichiers css / js chaque fois que vous déployez, quelque chose comme: screen.1233.css (le numéro peut être votre révision SVN si vous utilisez un système de version)

    • Diminuez-les pour optimiser les temps de chargement

    Pour mon développement, je trouve que Chrome a une excellente solution.

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

    Avec les outils de développement ouverts, cliquez simplement sur le bouton de rafraîchissement et lâchez-le une fois que vous avez survolé "Empty Cache and Hard Reload".

    C'est mon meilleur ami, et c'est une façon super légère d'obtenir ce que vous voulez!

    Have not found the client sided DOM approach creating the script node (or css) element dynamically:

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

    In Laravel (PHP) we can do it in following clear and elegant way (using file modification timestamp):

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

    And similar for CSS

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

    I put an MD5 hash of the file's contents in its URL. That way I can set a very long expiration date, and don't have to worry about users having old JS or CSS.

    I also calculate this once per file at runtime (or on file system changes) so there's nothing funny to do at design time or during the build process.

    If you're using ASP.NET MVC then you can check out the code in my other answer here .

    If you are using a modern browser, you could use a manifest file to inform the browsers which files need to be updated. This requires no headers, no versions in urls etc…

    For more details, see: See: https://developer.mozilla.org/nl/docs/Web/HTML/Applicatie_cache_gebruiken#Introduction

    I'm adding this answer as a SilverStripe http://www.silverstripe.org specific answer which I was looking for and never found but have worked out from reading: http://api.silverstripe.org/3.0/source-class-SS_Datetime.html#98-110

    Hopefully this will help someone using a SilverStripe template and trying to force reload a cached image on each page visit / refresh. In my case it is a gif animation which only plays once and therefor did not replay after it was cached. In my template I simply added:

     ?$Now.Format(dmYHis) 

    to the end of the file path to create a unique time stamp and to force the browser to treat it as a new file.

    It seems all answers here suggest some sort of versioning in the naming scheme, which has its downsides.

    Browsers should be well aware of what to cache and what not to cache by reading the webservers response, in particular the http headers – for how long is this resource valid ? was this resource updated since I last retrieved it ? etcetera.

    If things are configured 'correctly', just updating the files of your application should (at some point) refresh the browsers caches. You can for example configure your web server to tell the browser to never cache files (which is a bad idea).

    A more in-depth explanation of how that works is here https://www.mnot.net/cache_docs/#WORK

    My method to do this is simply to have the link element into a server-side include:

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

    where the contents of css-element.txt is

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

    so the day you want to link to my-new-css.css or whatever, you just change the include.

    Sorry for bringing back a dead thread.

    @ TomA is right.

    Using "querystring" method will not be cached as quoted by Steve Souders below:

    …that Squid, a popular proxy, doesn't cache resources with a querystring.

    @ TomA suggestion of using style.TIMESTAMP.css is good, but MD5 would be much better as only when the contents were genuinely changed, the MD5 changes as well.

    I see a problem with the approach of using a timestamp- or hash-based differentiator in the resource URL which gets stripped out on request at the server. The page that contains the link to eg the style sheet might get cached as well . So the cached page might request an older version of the style sheet but will be served the latest version, which might or might not work with the requesting page.

    To fix this, you either have to guard the requesting page with a no-cache header or meta, to make sure it gets refreshed on every load. Or you have to maintain all versions of the style file that you ever deployed on the server, each as an individual file and with their differentiator intact, so that the requesting page can get at the version of the style file it was designed for. In the latter case you basically tie the versions of the HTML page and the style sheet together, which can be done statically and doesn't require any server logic.