J'ai remarqué que certains navigateurs (en particulier, Firefox et Opera) sont très zélés dans l'utilisation des copies en cache des fichiers .css et .js, même entre les sessions de navigation. 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 en cache.
La question 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 devrait pas obliger le navigateur à recharger le fichier à chaque visite de la page. Je posterai 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.
Mise à jour :
Après avoir permis la discussion ici 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 : auto-versioning.
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 fausse chaîne de requête au fichier. (Un code Python permettant d'utiliser automatiquement l'horodatage comme chaîne de requête bidon a été soumis par pi). Cependant, la question de savoir si le navigateur mettrait en cache un fichier contenant une chaîne d'interrogation fait débat. (N'oubliez pas que nous voulons que le navigateur mette le fichier en cache et l'utilise lors de visites ultérieures. Nous voulons seulement qu'il aille chercher le fichier à nouveau lorsqu'il a été modifié).
Étant donné que ce qui se passe avec une fausse chaîne d'interrogation n'est pas clair, 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: Incorporation des commentaires de Nick Johnson que le regex original .htaccess
peut causer des problèmes avec des fichiers comme json-1.3.js
. La solution est de ne réécrire que s'il y a exactement 10 chiffres à la fin. (Parce que 10 chiffres couvrent tous les timestamps du 9/9/2001 au 20/11/2286).
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, 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, où que vous incluiez votre CSS, changez-le en ceci :
<link rel="stylesheet" href="/css/base.css" type="text/css" />
à ceci :
<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 de lien et l'utilisateur verra toujours le CSS le plus récent. Le navigateur pourra mettre le fichier CSS en cache, mais lorsque vous apporterez des modifications à votre CSS, le navigateur le verra comme une nouvelle URL et n'utilisera pas la copie en cache.
Cela peut également fonctionner avec les images, les favicons et le JavaScript. En fait, tout ce qui n'est pas généré dynamiquement.
Vous pouvez simplement mettre ?foo=1234
à la fin de votre import css / js, en changeant 1234 pour ce que vous voulez. Jetez un coup d'œil à la source html de SO pour un exemple.
L'idée est que les paramètres ? sont rejetés / ignorés lors de la requête de toute façon et que vous pouvez changer ce nombre lorsque vous lancez une nouvelle version.
Note : Il y a une certaine controverse quant à la manière exacte dont cela affecte la mise en cache. Je crois que l'idée générale est que les requêtes GET, avec ou sans paramètres, doivent être mises en cache, et que la solution ci-dessus devrait donc fonctionner.
Cependant, c'est à la fois 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 de toute façon demander une nouvelle version.
J'ai entendu parler de "versionnement 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 confs URL :
Voir aussi :