Contournement du cache via les paramètres

123

Nous voulons mettre en cache le buste sur les déploiements de production, mais ne pas perdre beaucoup de temps à trouver un système pour le faire. Ma pensée était d'appliquer un paramètre à la fin des fichiers css et js avec le numéro de version actuel:

<link rel="stylesheet" href="base_url.com/file.css?v=1.123"/>

Deux questions: cela cassera-t-il efficacement le cache? Le paramètre amènera-t-il le navigateur à ne jamais mettre en cache la réponse de cette URL puisque le paramètre indique qu'il s'agit d'un contenu dynamique?

Brad Herman
la source

Réponses:

115

Le paramètre ?v=1.123indique une chaîne de requête, et le navigateur pensera donc qu'il s'agit d'un nouveau chemin, par exemple ?v=1.0. Ainsi, il se charge à partir du fichier, pas du cache. Comme tu veux.

Et le navigateur supposera que la source restera la même la prochaine fois que vous appelez ?v=1.123et doit la mettre en cache avec cette chaîne. Il restera donc mis en cache, quelle que soit la configuration de votre serveur, jusqu'à ce que vous vous déplaciez vers ?v=1.124ou ainsi de suite.

Marshall
la source
4
Citant Steve Souders: "Pour bénéficier de la mise en cache par des proxys populaires, évitez de tourner avec une chaîne de requêtes et révisez plutôt le nom du fichier lui-même." L'explication complète peut être trouvée ici: stevesouders.com/blog/2008/08/23/…
lao
25
Ce billet de blog approche maintenant d'une décennie. Pensez-vous que les fournisseurs de cache et les CDN ne l'ont pas encore pris en charge? Squid semble être capable de mettre en cache des documents avec des chaînes de requête maintenant .
jeteon
1
Peut-être que cela aide quelqu'un: Personnellement, j'utilise l'horodatage de modification de fichier comme paramètre de version «automatique», par exemple. <link rel="stylesheet" href="style.css?v=1487935578" />
oelna
Je ne comprends pas personnellement pourquoi, mais Lara Hogan (Swanson) (responsable de l'ingénierie chez Etsy) ne recommande pas l'utilisation de paramètres de requête pour contourner le cache. Je pense que cela a à voir avec les proxys de cache entre l'utilisateur et le serveur.
Sam Rueby
36

Deux questions: cela cassera-t-il efficacement le cache?

Oui. Même Stack Overflow utilise cette méthode, même si je me souviens qu'ils (avec leurs millions de visiteurs par jour et des millions de versions et de configurations de client et de proxy différentes) ont eu des cas extrêmes où même cela n'était pas suffisant pour briser le cache. Mais l'hypothèse générale est que cela fonctionnera et constitue une méthode appropriée pour interrompre la mise en cache sur les clients.

Le paramètre amènera-t-il le navigateur à ne jamais mettre en cache la réponse de cette URL puisque le paramètre indique qu'il s'agit d'un contenu dynamique?

Non. Le paramètre ne changera pas la politique de mise en cache; les en-têtes de mise en cache envoyés par le serveur s'appliquent toujours, et s'il n'en envoie pas, les valeurs par défaut du navigateur.

Pekka
la source
1
@spender Je ne trouve pas la référence pour le moment, j'ai peur, il y avait un long article de blog ou une réponse SO où Jeff Atwood en parle (IIRC)
Pekka
2
@spender J'ai lu que certains serveurs proxy (anciens ou configurables pour) ignorent la chaîne de requête lors de la mise en cache.
MrWhite
2
@spender - J'ai entendu la même chose, et je pense que changer le nom du fichier ou le chemin est la meilleure option. Il peut être plus facile de simplement laisser déplacer tous vos fichiers statiques sous un nom de dossier versionné, par exemple, /static/v22/file.csscomme vous pouvez faire plusieurs fichiers avec un seul nom de dossier, par exemple /static/v23/file.csset/static/v23/mystuff.js
Brad Parks
22

Il est plus sûr de mettre le numéro de version dans le nom de fichier réel. Cela permet à plusieurs versions d'exister à la fois afin que vous puissiez déployer une nouvelle version et s'il existe encore des pages HTML mises en cache qui demandent l'ancienne version, elles obtiendront la version qui fonctionne avec leur HTML.

Notez que dans l'un des plus grands déploiements versionnés sur Internet, jQuery utilise les numéros de version dans le nom de fichier réel et permet en toute sécurité à plusieurs versions de coexister sans aucune logique particulière côté serveur (chaque version est juste un fichier différent).

Cela casse le cache une fois lorsque vous déployez de nouvelles pages et de nouveaux fichiers liés (ce que vous voulez) et à partir de là, ces versions peuvent être efficacement mises en cache (ce que vous voulez également).

jfriend00
la source
Je suis d'accord avec cela, mais il est beaucoup plus facile de simplement que Sinatra ajoute? V = <% = VERSION%> à toutes les requêtes css et js plutôt que d'avoir à contrôler chaque fichier individuellement. Finalement, nous passerons à sinatra-assetpack, qui pré-traitera et compressera tous les fichiers et ajoutera en fait une version # au nom de fichier, ce qui nous permettra ensuite de les contrôler individuellement beaucoup plus facilement.
Brad Herman
1
Je suis d'accord que le fait de mettre le numéro de version dans le nom du fichier est la solution la plus sûre si vous voulez être sûr à 10000%, mais je ne suis pas l'argument «plusieurs versions existent à la fois». Une URL avec un paramètre de requête est distincte de la même URL avec un paramètre de requête différent. Ils doivent être traités comme deux ressources différentes par le client; s'ils ne le sont pas, le client est cassé.
Pekka
2
@Pekka - le numéro de version peut permettre à plusieurs versions d'exister à la fois, mais cela nécessite la coopération du serveur pour mapper le paramètre de requête au fichier réel correct. Je ne pense pas que ce soit ce que fait l'OP ici et il y a peu de raisons d'exiger que cette complication lors de la modification du nom de fichier soit beaucoup plus simple et ne nécessite aucune coopération de serveur. De toute évidence, les deux peuvent fonctionner.
jfriend00
11

Comme d'autres l'ont dit, le contournement du cache avec un paramètre de requête est généralement considéré comme une mauvaise idée (tm), et ce depuis longtemps. Il est préférable de refléter la version dans le nom du fichier. Html5 Boilerplate recommande de ne pas utiliser la chaîne de requête, entre autres.

Cela dit, parmi les recommandations que j'ai vues qui citent une source, toutes semblent tirer leur sagesse d'un article de 2008 de Steve Souders. Ses conclusions sont basées sur le comportement des mandataires à l'époque, et elles peuvent ou non être pertinentes de nos jours. Pourtant, en l'absence d'informations plus récentes, changer le nom du fichier est l'option la plus sûre.

changement de hachage
la source
9

Il va casser le cache une fois, après que le client a téléchargé la ressource, toutes les autres réponses seront servies à partir du cache client à moins que:

  1. le paramètre v est mis à jour.
  2. le client efface son cache
ncremins
la source
6

En général, cela devrait être bien, mais il est possible que cela ne fonctionne pas s'il existe un cache intermédiaire (un proxy) configuré pour ignorer les paramètres de la requête.

Par exemple, si vous diffusez du contenu statique via Akamai CDN, il peut être configuré pour ignorer les paramètres de requête afin d'éviter le contournement du cache à l'aide de cette méthode.

Ken Liu
la source
5

Cela dépend beaucoup de la robustesse de votre mise en cache. Par exemple, le serveur proxy squid (et peut-être d'autres) par défaut ne met pas en cache les URL servies avec une chaîne de requêtes - du moins, il l'a fait lorsque cet article a été écrit. Si certains cas d'utilisation ne vous dérangent pas, provoquant des erreurs de cache inutiles, continuez avec les paramètres de requête. Mais il est très facile de mettre en place un schéma de contournement du cache basé sur les noms de fichiers qui évite ce problème.

Bobby Jack
la source
5
Le proxy squid qui a été cité dans l'article de Steve Souders a changé sa politique de mise en cache par défaut. Depuis la version 2.7 (mai 2008) et la version 3.1 (mars 2010), le comportement par défaut est de mettre en cache le contenu dynamique.
Josh Rack
5

Nous avons trouvé une comparaison des 2 techniques (chaîne de requête vs nom de fichier) ici :

La version en tant que chaîne de requête a deux problèmes.

Premièrement, ce n'est peut-être pas toujours un navigateur qui implémente la mise en cache à travers laquelle nous devons nous arrêter. On dit que certains proxys (peut-être plus anciens) ignorent la chaîne de requête en ce qui concerne leur comportement de mise en cache.

Deuxièmement, dans certains scénarios de déploiement plus complexes, où vous avez plusieurs serveurs frontaux et / ou plusieurs serveurs principaux, une mise à niveau est tout sauf instantanée. Vous devez être en mesure de diffuser à la fois l'ancienne et la nouvelle version de vos éléments. Découvrez par exemple comment cela vous affecte lorsque vous utilisez Google App Engine.

utilisateur
la source
4

Une autre approche similaire consiste à utiliser htaccess mod_rewrite pour ignorer une partie du chemin lors de la diffusion des fichiers. Votre page d'index jamais mise en cache fait référence au dernier chemin d'accès aux fichiers.

Du point de vue du développement, c'est aussi simple que d'utiliser des paramètres pour le numéro de version, mais c'est aussi robuste que l'approche du nom de fichier.

Utilisez la partie ignorée du chemin pour le numéro de version, et le serveur l'ignore simplement et sert le fichier non mis en cache.

1.2.3/css/styles.csssert le même fichier que css/styles.cssdepuis que le premier répertoire est supprimé et ignoré par le fichier htaccess

Y compris les fichiers versionnés

<?php
  $version = "1.2.3";
?>

<html>
  <head>
    <meta http-equiv="cache-control" content="max-age=0" />
    <meta http-equiv="cache-control" content="no-cache" />
    <meta http-equiv="expires" content="0" />
    <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
    <meta http-equiv="pragma" content="no-cache" />
    <link rel="stylesheet" type="text/css" href="<?php echo $version ?>/css/styles.css">
  </head>
  <body>
    <script src="<?php echo $version ?>/js/main.js"></script>
  </body>
</html>

Notez que cette approche signifie que vous devez désactiver la mise en cache de votre page d'index - Utilisation des balises <meta> pour désactiver la mise en cache dans tous les navigateurs?

fichier .htaccess

RewriteEngine On

# if you're requesting a file that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-f 
# likewise if a directory that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-d 

# otherwise, rewrite foo/bar/baz to bar/baz - ignore the first directory
RewriteRule ^[^/]+/(.+)$ $1 [L] 

Vous pouvez adopter la même approche sur n'importe quelle plate-forme de serveur permettant la réécriture d'url

(condition de réécriture adaptée de mod_rewrite - réécriture du répertoire dans la chaîne de requête sauf / #! / )

... et si vous avez besoin d'un contournement du cache pour votre page d'index / point d'entrée de site, vous pouvez toujours utiliser JavaSript pour l'actualiser.

Alexanderbird
la source
2
<script type="text/javascript">
// front end cache bust

var cacheBust = ['js/StrUtil.js', 'js/protos.common.js', 'js/conf.js', 'bootstrap_ECP/js/init.js'];   
for (i=0; i < cacheBust.length; i++){
     var el = document.createElement('script');
     el.src = cacheBust[i]+"?v=" + Math.random();
     document.getElementsByTagName('head')[0].appendChild(el);
}
</script> 
Conete Cristian
la source
Lors du développement / test de nouvelles versions, le cache peut être un problème car le navigateur, le serveur et même parfois l'opérateur de télécommunications 3G (si vous effectuez un déploiement mobile) mettront en cache le contenu statique (par exemple JS, CSS, HTML, img). Vous pouvez résoudre ce problème en ajoutant le numéro de version, le nombre aléatoire ou l'horodatage à l'URL, par exemple: JSP: <script src = "js / excel.js? Time = <% = new java.util.Date ()%>"> </ script> Dans le cas où vous utilisez du HTML pur (au lieu des pages serveur JSP, ASP, PHP), le serveur ne vous aidera pas. Dans le navigateur, les liens sont chargés avant l'exécution du JS, vous devez donc supprimer les liens et les charger avec JS
Conete Cristian
Je ne pense pas que cela chargera les fichiers JS dans l'ordre, de manière synchrone.
Stealth Rabbi
0
 <script>
    var storedSrcElements = [
         "js/exampleFile.js",
         "js/sampleFile.js",
         "css/style.css"
          ];

    var head= document.getElementsByTagName('head')[0];
    var script;
    var link;
    var versionNumberNew = 4.6;

    for(i=0;i<storedSrcElements.length;i++){
     script= document.createElement('script');
     script.type= 'text/javascript';
     script.src= storedSrcElements[i] + "?" + versionNumberNew;
     head.appendChild(script);
    }     


     </script> 


       ### Change the version number  (versionNumberNew) when you want the new files to be loaded  ###
Teja
la source
0

J'espère que cela devrait vous aider à injecter un fichier JS externe

<script type="text/javascript"> 
var cachebuster = Math.round(new Date().getTime() / 1000); 
document.write('<scr'+'ipt type="text/javascript" src="external.js?cb=' +cachebuster+'"></scr' + 'ipt>');
</script>

Source - Code Cachebuster en JavaScript

Vinit Kadkol
la source