J'ai remarqué que certains navigateurs (notamment Firefox et Opera) sont très zélés pour utiliser des copies en cache des fichiers .css et .js , même entre les sessions du navigateur. Cela pose un problème lorsque vous mettez à jour l'un de ces fichiers mais que le navigateur de l'utilisateur continue à utiliser la copie mise en cache.
La question qui se pose est la suivante: quel est le moyen le plus élégant de forcer le navigateur de l'utilisateur à recharger le fichier lorsqu'il a été modifié?
Idéalement, la solution ne forcerait pas le navigateur à recharger le fichier à chaque visite sur la page. Je vais poster ma propre solution comme réponse, mais je suis curieux de savoir si quelqu'un a une meilleure solution et je laisserai vos votes décider.
Mettre à jour:
Après avoir autorisé la discussion pendant un certain temps, j'ai trouvé la suggestion de John Millikin et da5id utile. Il s'avère qu'il existe un terme pour cela: version-automatique .
J'ai posté une nouvelle réponse ci-dessous qui est une combinaison de ma solution d'origine et de la suggestion de John.
Une autre idée suggérée par SCdF serait d’ajouter une fausse chaîne de requête au fichier. (Certains codes Python utilisant automatiquement l'horodatage en tant que chaîne de requête fictive ont été soumis par pi .). Cependant, des discussions sont en cours pour savoir si le navigateur mettrait en cache un fichier avec une chaîne de requête. (Rappelez-vous que nous voulons que le navigateur mette en cache le fichier et l’utilise lors de visites ultérieures. Nous voulons seulement qu’il récupère le fichier à nouveau lorsqu’il a été modifié.)
Puisqu'il n'est pas clair ce qui se passe avec une chaîne de requête fictive, 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 langages.
Mise à jour 2: Intégration des commentaires de Nick Johnson que la regex .htaccess
d'origine peut provoquer des problèmes avec des fichiers tels que json-1.3.js
. La solution est de ne réécrire que s’il ya exactement 10 chiffres à la fin. (Parce que 10 chiffres couvrent tous les horodatages du 09/09/2001 au 11/20/2286.)
Premièrement, 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, 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);
}
Maintenant, partout où vous incluez votre CSS, changez-le:
<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 n’aurez plus jamais à modifier la balise link et l’utilisateur verra toujours le dernier CSS. Le navigateur pourra mettre en cache le fichier CSS, mais lorsque vous apportez des modifications à votre CSS, le navigateur le verra comme une nouvelle URL, de sorte qu'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. Il existe donc plusieurs techniques, selon que vous résolvez le problème vous-même lorsque vous développez un site Web ou que 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 celle que vous rencontrez lorsque vous développez le site. Étant donné que le visiteur moyen visite moins fréquemment le site (peut-être que quelques fois par mois, sauf si vous êtes un réseau Google ou hi5), il est moins probable que vos fichiers soient stockés dans le cache, ce qui peut être suffisant. Si vous souhaitez imposer une nouvelle version dans le navigateur, vous pouvez toujours ajouter une chaîne de requête à la demande et augmenter le numéro de version lorsque vous apportez des modifications importantes:
<script src="/myJavascript.js?version=4"></script>
Cela garantira que tout le monde recevra le nouveau fichier. Cela fonctionne parce que le navigateur examine l'URL du fichier pour déterminer s'il a une copie en cache. Si votre serveur n'est pas configuré pour faire quoi que ce soit avec la chaîne de requête, celle-ci sera ignorée, mais le nom ressemblera à un nouveau fichier du navigateur.
Par contre, 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 fastidieux.
Ainsi, pendant que vous développez votre site, un bon truc 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>
Ajouter une chaîne de requête à la requête est un bon moyen de mettre à jour 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 forcément avare de garder les fichiers en cache. Les navigateurs ont des stratégies pour ce genre de choses et ils respectent généralement les règles définies dans la spécification HTTP. Lorsqu'un navigateur adresse une requête à un serveur, une partie de la réponse est un en-tête EXPIRES. Une date indiquant au navigateur combien de temps elle doit être conservée dans le cache. La prochaine fois que le navigateur rencontre une demande pour le même fichier, il voit qu'il en a une copie dans le cache et recherche la date EXPIRES pour décider s'il doit être utilisé.
Alors, croyez-le ou non, c'est en fait votre serveur qui rend le cache du navigateur si persistant. Vous pouvez ajuster les paramètres de votre serveur et changer les en-têtes EXPIRES, mais la petite technique que j'ai décrite ci-dessus est probablement un moyen beaucoup plus simple. Étant donné que la mise en cache est bonne, vous souhaitez généralement définir cette date dans un avenir lointain (un "En-tête d'expiration de futur lointain") et utiliser la technique décrite ci-dessus pour forcer une modification.
Si vous souhaitez en savoir plus sur HTTP ou sur la manière dont ces demandes sont formulées, voici un bon livre: "Sites Web haute performance" de Steve Souders. C'est une très bonne introduction au sujet.
Le module mod_pagespeed de Google pour Apache effectuera automatiquement le contrôle de version. C'est vraiment glissant.
Il analyse le code HTML lors de sa sortie du serveur Web (fonctionne avec PHP, Rails, python, HTML statique, etc.) et réécrit les liens vers les fichiers CSS, JS et les images afin qu'ils incluent un code d'identification. Il sert les fichiers sur les URL modifiées avec un très long contrôle de cache. Lorsque les fichiers changent, les URL sont automatiquement modifiées et le navigateur doit les récupérer à nouveau. En gros, cela fonctionne, sans aucune modification de votre code. Cela réduira même votre code à la sortie.
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 supprimer le hachage, mais l’avantage est que vous pouvez maintenant définir votre stratégie de cache sur "Cache pour toujours", car si l’URL est la même, le fichier n’est pas modifié.
Vous pouvez ensuite écrire un script Shell simple qui calcule le hachage du fichier et met à jour votre balise (vous voudrez probablement le déplacer dans un fichier séparé pour l'inclusion).
Exécutez simplement ce script chaque fois que CSS change et que vous êtes bon. Le navigateur ne rechargera que vos fichiers quand ils sont modifiés. Si vous effectuez une modification, puis l'annulez, il n'y a aucune difficulté à déterminer la version à laquelle vous devez revenir pour que vos visiteurs ne puissent pas télécharger à nouveau.
Vous ne savez pas pourquoi vous prenez tant de peine à mettre en œuvre cette solution.
Il vous suffit de récupérer l'horodatage modifié du fichier et de l'ajouter en tant que chaîne de requête au fichier.
Dans PHP, je le ferais comme:
<link href="mycss.css?v=<?= filemtime('mycss.css') ?>" rel="stylesheet">
filemtime est une fonction PHP qui renvoie l'horodatage du fichier modifié.
Vous pouvez simplement mettre ?foo=1234
à la fin de votre import css/js, en changeant 1234 pour être ce que vous préférez. Jetez un œil à la source HTML SO pour un exemple.
L'idée étant que le? les paramètres sont quand même ignorés/ignorés dans la demande et vous pouvez changer ce nombre lorsque vous déployez une nouvelle version.
Remarque: Il existe certains arguments concernant la manière dont cela affecte la mise en cache. Je crois que l’essentiel en est que les requêtes GET, avec ou sans paramètres devraient être masquables, donc la solution ci-dessus devrait fonctionner.
Cependant, il appartient au serveur Web de décider s’il souhaite adhérer à cette partie de la spécification et au navigateur utilisé par l’utilisateur, car il peut simplement aller de l'avant et demander de toute façon une nouvelle version.
J'ai entendu parler de "versioning automatique". La méthode la plus courante consiste à inclure le mtime du fichier statique quelque part dans l'URL et à le supprimer en utilisant des gestionnaires de réécriture ou des conf de type URL:
Voir également:
Les quelque 30 réponses existantes sont un excellent conseil pour un site Web circa 2008. Cependant, s’il s’agit d’une application moderne page unique (SPA), il est peut-être temps de repenser certaines hypothèses fondamentales… en particulier l’idée selon laquelle il est souhaitable que le serveur Web ne serve que la seule solution la plus simple. version récente d'un fichier.
Imaginez que vous soyez un utilisateur ayant la version M d'un SPA chargée dans votre navigateur:
/some.template
/some.template
- voulez-vous qu'il renvoie la version M ou N du modèle?Si le format de /some.template
a changé entre les versions M et N (ou si le fichier a été renommé ou autre) vous ne souhaiterez probablement pas la version N du modèle envoyé au navigateur qui exécute l'ancienne version M de l'analyseur. †
Les applications Web rencontrent ce problème lorsque deux conditions sont remplies:
Une fois que votre application doit servir plusieurs versions en parallèle, résoudre le cache et le "rechargement" devient trivial:
/v<release_tag_1>/…files…
, /v<release_tag_2>/…files…
<script>
et <link>
, etc. pour qu'elles pointent vers ce fichier dans l'un des répertoires versionnésCette dernière étape semble délicate, car elle pourrait nécessiter l’appel d’un générateur d’URL pour chaque URL de votre code côté serveur ou côté client. Vous pouvez également utiliser intelligemment la balise <base>
et modifier la version actuelle à un endroit.
† Une solution consiste à forcer le navigateur à tout recharger lors de la publication d'une nouvelle version. Toutefois, afin de laisser les opérations en cours terminées, il peut toujours être plus simple de prendre en charge au moins deux versions en parallèle: v-current et v-previous.
Ne pas utiliser foo.css? Version = 1! Les navigateurs ne sont pas supposés mettre en cache les URL contenant des variables GET. Selon http://www.thinkvitamin.com/features/webapps/serving-javascript-fast , bien que IE et Firefox l'ignorent, Opera et Safari ne le font pas! À la place, utilisez foo.v1234.css et utilisez des règles de réécriture pour supprimer le numéro de version.
Pour ASP.NET 4.5 et versions ultérieures, vous pouvez utiliser groupement de scripts .
La requête
http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81
concerne l'ensemble AllMyScripts et contient une paire de chaînes de requête v = r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81. La chaîne de requête v a un jeton de valeur qui est un identificateur unique utilisé pour la mise en cache. Tant que le bundle ne change pas, l'application ASP.NET demandera le bundle AllMyScripts à l'aide de ce jeton. Si un fichier de l'ensemble est modifié, l'infrastructure d'optimisation ASP.NET génère un nouveau jeton, garantissant que les demandes de navigateur relatives à l'ensemble obtiendront le dernier ensemble.
Le groupement présente d'autres avantages, notamment une augmentation des performances lors du premier chargement de page avec minification.
RewriteRule nécessite une petite mise à jour pour les fichiers js ou css contenant un contrôle de version en notation point à la fin. Par exemple. json-1.3.js.
J'ai ajouté une classe de négation de points [^.] À la regex so. Number. est ignoré.
RewriteRule ^(.*)\.[^.][\d]+\.(css|js)$ $1.$2 [L]
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 cherchera la dernière fois que l'utilisateur a visité votre site. Si la dernière visite a eu lieu avant la publication du nouveau code, il utilise location.reload(true)
pour forcer l'actualisation de la page à partir du serveur.
Ce script est généralement le tout premier script du <head>
et est donc évalué avant le chargement de tout autre contenu. Si un rechargement doit avoir lieu, il est à peine perceptible par l'utilisateur.
J'utilise le stockage local pour stocker l'horodatage de la dernière visite sur le navigateur, mais vous pouvez ajouter des cookies au mixage si vous souhaitez prendre en charge les anciennes versions d'IE.
Post intéressant. Après avoir lu toutes les réponses ici combinées au fait que je n’ai jamais eu de problèmes avec les chaînes de requête "fictives" (dont je ne sais pas pourquoi tout le monde hésite à utiliser cela), je suppose que la solution (qui élimine la nécessité de règles de réécriture Apache comme dans la réponse acceptée) consiste à calculer un bref HASH du contenu du fichier CSS (au lieu du fichier datetime) en tant que chaîne de requête bidon.
Cela se traduirait par:
<link rel="stylesheet" href="/css/base.css?[hash-here]" type="text/css" />
Bien entendu, les solutions datetime se chargent également de l'édition d'un fichier CSS, mais je pense qu'il s'agit du contenu du fichier css et non du fichier datetime, alors pourquoi les mélanger?
En Laravel (PHP), nous pouvons le faire de manière claire et élégante (en utilisant l’horodatage de modification de fichier):
<script src="{{ asset('/js/your.js?v='.filemtime('js/your.js')) }}"></script>
Et similaire pour CSS
<link rel="stylesheet" href="{{asset('css/your.css?v='.filemtime('css/your.css'))}}">
Merci à Kip pour sa solution parfaite!
Je l'ai étendu pour l'utiliser comme un Zend_view_Helper. Parce que mon client exécute sa page sur un hôte virtuel, je l'ai également étendue pour cela.
J'espère que ça 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;
}
}
}
}
Salut et merci.
Nous n'avons pas trouvé l'approche DOM côté client créant le nœud de script (ou css) de manière dynamique:
<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>
Vous pouvez simplement ajouter un nombre aléatoire avec l'URL CSS/JS comme
example.css?randomNo=Math.random()
Supposons que vous ayez un fichier disponible sur:
/styles/screen.css
vous pouvez soit ajouter un paramètre de requête avec les informations de version sur l’URI, par exemple:
/styles/screen.css?v=1234
ou vous pouvez ajouter des informations sur la version, par exemple:
/v/1234/styles/screen.css
IMHO la deuxième méthode est préférable pour les fichiers CSS car ils peuvent faire référence à des images en utilisant des URL relatives, ce qui signifie que si vous spécifiez un 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 cela comme une nouvelle ressource et n'utilisera pas une version mise en cache. Si vous basez votre numéro de version sur le fichier Subversion/CVS/etc. révision cela 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 l’URL images/happy.gif
relative à /styles/screen.css?v=1235
est /styles/images/happy.gif
et ne contient aucune information de version.
J'ai implémenté une solution de mise en cache en utilisant cette technique avec des servlets Java et je gère simplement les demandes adressées à /v/*
avec un servlet qui délègue à la ressource sous-jacente (c'est-à-dire /styles/screen.css
). En mode de développement, je définis des en-têtes de mise en cache qui indiquent au client de toujours vérifier la fraîcheur de la ressource auprès du serveur (le résultat est généralement 304 si vous déléguez à la variable DefaultServlet
de Tomcat et le fichier .css
, .js
, etc. n'a pas changé) en mode de déploiement, je définis les en-têtes qui disent "cache pour toujours".
Vous pouvez forcer une "mise en cache à l'échelle de la session" si vous ajoutez l'identifiant de session en tant que paramètre spureous du fichier js/css:
<link rel="stylesheet" src="myStyles.css?ABCDEF12345sessionID" />
<script language="javascript" src="myCode.js?ABCDEF12345sessionID"></script>
Si vous souhaitez une mise en cache à l'échelle de la version, vous pouvez ajouter du 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>
Pour ASP.NET, je suppose que la solution suivante comportera des options avancées (mode débogage/libération, versions):
Fichiers Js ou Css inclus de cette manière:
<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();
}
...
}
google chrome a Hard Reload ainsi que Vider le cache et Hard Reload option.Vous pouvez cliquer et maintenir le bouton de rechargement (En mode inspection) pour en sélectionner un.
J'ai récemment résolu ce problème 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">
Bien entendu, l’avantage est que vous n’aurez plus jamais à changer votre code HTML. Si vous touchez le fichier CSS, une invalidation du cache sera automatiquement déclenchée. Fonctionne très bien et les frais généraux ne sont pas perceptibles.
Pour mon développement, je trouve que le chrome est une excellente solution.
https://developer.chrome.com/devtools/docs/tips-and-tricks#hard-reload
Avec les outils de développement ouverts, il suffit de cliquer longuement sur le bouton d'actualisation et de relâcher une fois que vous passez la souris sur "Vider le cache et recharger physiquement".
Ceci est mon meilleur ami, et est un moyen super léger d'obtenir ce que vous voulez!
J'ajoute cette réponse sous la forme SilverStripe http://www.silverstripe.org réponse spécifique que je cherchais et que je n'avais jamais trouvée mais que j'ai résolue en lisant: http://api.silverstripe.org /3.0/source-class-SS_Datetime.html#98-110
J'espère que cela aidera quelqu'un utilisant un modèle SilverStripe et essayant de forcer le rechargement d'une image en cache à chaque visite/actualisation de page. Dans mon cas, il s’agit d’une animation gif qui ne se lit qu’une fois et qui n’a donc pas été rejouée après sa mise en cache. Dans mon modèle, j'ai simplement ajouté:
?$Now.Format(dmYHis)
à la fin du chemin du fichier pour créer un horodatage unique et obliger le navigateur à le traiter comme un nouveau fichier.
Désolé de ramener un fil mort.
@ TomA a raison.
L'utilisation de la méthode "querystring" ne sera pas mise en cache comme indiqué par Steve Souders ci-dessous:
... que Squid, un proxy populaire, ne cache pas les ressources avec un chaîne de requête.
@ TomA La suggestion d'utiliser style.TIMESTAMP.css est bonne, mais MD5 serait bien meilleure, car ce n'est que lorsque le contenu est véritablement modifié que le MD5 change également.
Il semble que toutes les réponses suggèrent une sorte de version dans le schéma de nommage, ce qui a ses inconvénients.
Les navigateurs doivent bien savoir quoi mettre en cache et ne pas mettre en cache en lisant la réponse du serveur Web, en particulier les en-têtes http - pendant combien de temps cette ressource est-elle valide? cette ressource a-t-elle été mise à jour depuis la dernière fois que je l'ai récupérée? etc.
Si les choses sont configurées «correctement», la mise à jour des fichiers de votre application devrait (à un moment donné) actualiser les caches des navigateurs. Vous pouvez par exemple configurer votre serveur Web pour indiquer au navigateur de ne jamais mettre en cache les fichiers (ce qui est une mauvaise idée).
Vous trouverez une explication plus détaillée de la procédure à suivre ici https://www.mnot.net/cache_docs/#WORK
Je mets un hachage MD5 du contenu du fichier dans son URL. De cette façon, je peux définir une date d'expiration très longue et je n'ai pas à m'inquiéter du fait que les utilisateurs ont de vieux JS ou CSS.
Je calcule également cela une fois par fichier au moment de l'exécution (ou lors des modifications du système de fichiers), de sorte qu'il n'y a rien de drôle à faire au moment de la conception ou du processus de construction.
Si vous utilisez ASP.NET MVC, vous pouvez vérifier le code dans mon autre réponse ici .
Utilisez simplement le code côté serveur pour ajouter la date du fichier ... ainsi, il SERA mis en cache et rechargé uniquement lorsque le fichier sera modifié
En 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>
Je suggère de mettre en œuvre le processus suivant:
version 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
les minimiser pour optimiser les temps de chargement
Pour un environnement Java Servlet, vous pouvez consulter la bibliothèque Jawr . La page de fonctionnalités explique comment elle gère la mise en cache:
Jawr fera de son mieux pour forcer vos clients à mettre en cache les ressources. Si un navigateur demande si un fichier a été modifié, un en-tête 304 (non modifié) est renvoyé sans contenu. D'autre part, avec Jawr, vous serez à 100% sûr que les nouvelles versions de vos ensembles seront téléchargées par tous les clients. Chaque URL vers vos ressources inclura un préfixe basé sur le contenu, généré automatiquement, qui change automatiquement chaque fois qu'une nouvelle ressource est mise à jour. Une fois que vous aurez déployé une nouvelle version, l'URL de l'ensemble changera également, de sorte qu'il sera impossible qu'un client utilise une version mise en cache plus ancienne.
La bibliothèque effectue également la minification js/css, mais vous pouvez la désactiver si vous ne le souhaitez pas.
Si vous utilisez git + php, vous pouvez recharger le script à partir du cache chaque fois que le dépôt git est modifié, à l'aide du code suivant:
exec('git rev-parse --verify HEAD 2> /dev/null', $gitLog);
echo ' <script src="/path/to/script.js"?v='.$gitLog[0].'></script>'.PHP_EOL;
Ajoutez simplement ce code là où vous souhaitez effectuer un rechargement difficile (forcez le navigateur à recharger les fichiers CSS/JS mis en cache) Faites-le dans le fichier .load pour qu'il ne soit pas actualisé comme une boucle
$( window ).load(function() {
location.reload(true);
});
Si vous utilisez un navigateur moderne, vous pouvez utiliser un fichier manifeste pour indiquer aux navigateurs quels fichiers doivent être mis à jour. Cela ne nécessite aucun en-tête, aucune version dans les URL, etc.
Pour plus de détails, voir: Voir: https://developer.mozilla.org/nl/docs/Web/HTML/Applicatie_cache_gebruiken#Introduction
Je vois un problème avec l'approche consistant à utiliser un différenciateur basé sur un horodatage ou un hachage dans l'URL de la ressource, qui est supprimé à la demande du serveur. La page qui contient le lien vers par exemple la feuille de style peut également être mise en cache . Ainsi, la page en cache peut demander une version plus ancienne de la feuille de style, mais la dernière version lui sera servie, ce qui peut ou non fonctionner avec la page demandée.
Pour résoudre ce problème, vous devez protéger la page demandeuse avec un en-tête no-cache
ou une méta afin de vous assurer qu'elle est actualisée à chaque chargement. Ou vous devez conserver toutes les versions du fichier de style que vous avez déjà déployé sur le serveur, chacune en tant que fichier individuel avec son différentiateur intact, afin que la page demandeuse puisse obtenir la version du fichier de style qu'il était conçu pour. Dans ce dernier cas, vous associez essentiellement les versions de la page HTML et de la feuille de style, ce qui peut être fait de manière statique et ne nécessite aucune logique de serveur.
"Une autre idée suggérée par SCdF serait d’ajouter une chaîne de requête fictive au fichier. (Un code Python utilisait automatiquement l’horodatage en tant que chaîne de requête fictive soumise par pi.) Cependant, il existe une discussion sur la pas le navigateur ne mettrait en cache un fichier avec une chaîne de requête (rappelez-vous que nous voulons que le navigateur mette le fichier en cache et l’utilise lors de visites ultérieures. Nous ne voulons qu’il récupère le fichier à nouveau lorsqu’il a été modifié.) que se passe-t-il avec une fausse chaîne de requête, je n'accepte pas cette réponse ".
<link rel = "stylesheet" href = "file.css? <? = hash_hmac ('sha1', id_session (), md5_file (" file.css "));?>" />
Le hachage du fichier signifie que, quand il aura changé, la chaîne de requête aura changé. Si ce n'est pas le cas, cela restera le même. Chaque session impose également un rechargement.
Facultativement, vous pouvez également utiliser les réécritures pour que le navigateur pense qu'il s'agit d'un nouvel URI.
Désactiver le cache de script.js uniquement pour le développement local en JS pur
injecte script.js au hasard? wizardry = 1231234 et bloque le script.js normal
<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">
Une autre suggestion pour les sites Web ASP.Net,
Je suis arrivé à cette question lorsque je cherchais une solution pour mon SPA, qui ne dispose que d’un seul index.html répertoriant tous les fichiers nécessaires. Bien que j'ai eu quelques pistes qui m'ont aidé, je n'ai pas pu trouver de solution rapide et facile.
En fin de compte, j’ai écrit une petite page (comprenant tout le code) nécessaire à la conversion automatique d’un fichier html/js index.html dans le cadre du processus de publication. Cela fonctionne parfaitement et ne met à jour que les nouveaux fichiers en fonction de la date de la dernière modification.
Vous pouvez voir mon message sur http://blueskycont.com/wp/2016/05/12/autoversion-your-spa-index-html/ . Il y a un winapp de travail gratuit là aussi.
Le courage du code est
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");
}
De nombreuses réponses suggèrent d'ajouter un horodatage à l'URL. Sauf si vous modifiez directement vos fichiers de production, l'horodatage du fichier ne reflète probablement pas l'heure à laquelle un fichier a été modifié. Dans la plupart des cas, l’URL changera plus souvent que le fichier lui-même. C'est pourquoi vous devez utiliser un hachage rapide du contenu du fichier, tel que MD5 tel que le suggère Levik et d'autres.
Gardez à l'esprit que la valeur doit être calculée une fois lors de la génération ou de l'exécution, plutôt que chaque fois que le fichier est demandé.
A titre d'exemple, voici un script bash simple qui lit une liste de noms de fichiers à partir de stdin et écrit un fichier json contenant des hachages sur stdout:
#!/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 "}"
Ce fichier peut ensuite être chargé au démarrage du serveur et référencé au lieu de lire le système de fichiers.
Si vous êtes un développeur cherchant à éviter la mise en cache, l’onglet chrome du réseau dispose de l’option de désactivation du cache. Sinon, vous pouvez le faire sans une structure de rendu de serveur utilisant deux balises de script.
<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>
L’une des approches les meilleures et rapides que je connaisse consiste à changer le nom du dossier dans lequel vous avoir des fichiers CSS ou JS . OR pour les développeurs . Modifiez le nom de vos fichiers CSS/js en quelque sorte comme des versions.
<link rel="stylesheet" href="cssfolder/somecssfile-ver-1.css"/>
Faites la même chose pour vos fichiers js.
Ma méthode pour faire cela est simplement d'avoir l'élément link dans un côté serveur:
<!--#include virtual="/includes/css-element.txt"-->
où le contenu de css-element.txt est
<link rel="stylesheet" href="mycss.css"/>
ainsi, le jour où vous souhaitez créer un lien vers my-new-css.css ou autre, vous devez simplement modifier l'inclusion.
Petite amélioration par rapport aux réponses existantes ...
L'utilisation d'un numéro aléatoire ou d'un identifiant de session entraînerait le rechargement de chaque demande. Idéalement, nous n’aurons peut-être besoin de changer que si des modifications de code ont été effectuées dans n’importe quel fichier js/css. Lorsque vous utilisez un fichier JSP commun en tant que modèle pour de nombreux autres fichiers jsp et js Ajoutez ci-dessous le fichier JSP commun
<%@ taglib prefix="c" uri="http://Java.Sun.com/jsp/jstl/core"%>
<c:set var = "version" scope = "application" value = "1.0.0" />
Maintenant, utilisez la variable ci-dessus dans tous les emplacements comme indiqué ci-dessous dans vos inclusions de fichier js.
<script src='<spring:url value="/js/myChangedFile.js?version=${version}"/>'></script>
Avantages:
1) Cette approche vous aidera à changer le numéro de version d’un seul emplacement.
2) Maintenir le bon numéro de version (habituellement le numéro de build/release) vous aidera à vérifier/vérifier que les modifications de code sont correctement déployées (à partir de la console de développeur du navigateur.
Un autre conseil utile:
Si vous utilisez le navigateur Chrome, vous pouvez désactiver la mise en cache lorsque l'outil de développement est ouvert . Dans Chrome, appuyez sur F12> F1, puis sélectionnez Paramètres> Préférences> Réseau> Désactiver la mise en cache (lorsque DevTools est ouvert).
Eh bien, je le fais fonctionner à ma façon en changeant la version de js chaque fois que la page se charge en ajoutant un nombre aléatoire à la version du fichier js comme suit:
// Add it to the top of the page
<?php
srand();
$random_number = Rand();
?>
Appliquez ensuite le nombre aléatoire à la version js comme suit:
<script src="file.js?version=<?php echo $random_number;?>"></script>