Je me moquais des moyens de mettre en cache les actifs de mon site Web et j'ai remarqué que la plupart des sites Web similaires au mien utilisent des chaînes de requête pour remplacer la mise en cache (par exemple: /css/style.css?v=124942823)
Ensuite, j'ai remarqué que chaque fois que j'enregistrais mon fichier style.css, les derniers en-têtes modifiés étaient "mis à jour", rendant la chaîne de requête inutile.
Je me demande donc:
Pourquoi tant de sites Web utilisent-ils la méthode "chaîne de requête", au lieu de laisser le dernier en-tête modifié faire son travail?
La modification de la chaîne de requête modifie l'URL, garantissant que le contenu est "frais".
Dois-je supprimer l'en-tête Last-modified et simplement travailler avec des chaînes de requête?
Non. Bien que ce soit presque la bonne réponse.
Il existe trois stratégies de mise en cache de base utilisées sur le Web:
Pour illustrer les trois, envisagez le scénario suivant:
Un utilisateur accède à un site Web pour la première fois, charge dix pages et quitte. Chaque page charge le même fichier css. Pour chacune des stratégies de mise en cache ci-dessus, combien de demandes seraient effectuées?
Dans ce scénario, il doit être clair que rien d'autre n'influence le résultat, 10 demandes pour le fichier css entraîneraient son envoi au client (navigateur) 10 fois.
Si Last-Modified ou Etag sont utilisés, il y aura aussi 10 demandes. Cependant, 9 d'entre eux ne seront que les en-têtes et aucun corps n'est transféré. Les clients utilisent des demandes conditionnelles pour éviter de retélécharger quelque chose qu'il a déjà. Prenons par exemple le fichier css de ce site.
La toute première fois que le fichier est demandé, les événements suivants se produisent:
$ curl -i http://cdn.sstatic.net/stackoverflow/all.css
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 12 May 2014 07:38:31 GMT
Content-Type: text/css
Connection: keep-alive
Set-Cookie: __cfduid=d3fa9eddf76d614f83603a42f3e552f961399880311549; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.sstatic.net; HttpOnly
Cache-Control: public, max-age=604800
Last-Modified: Wed, 30 Apr 2014 22:09:37 GMT
ETag: "8026e7dfc064cf1:0"
Vary: Accept-Encoding
CF-Cache-Status: HIT
Expires: Mon, 19 May 2014 07:38:31 GMT
CF-RAY: 1294f50b2d6b08de-CDG
.avatar-change:hover{backgro.....Some KB of content
Une demande ultérieure pour la même URL ressemblerait à ceci:
$ curl -i -H "If-Modified-Since:Wed, 30 Apr 2014 22:09:37 GMT" http://cdn.sstatic.net/stackoverflow/all.css
HTTP/1.1 304 Not Modified
Server: cloudflare-nginx
Date: Mon, 12 May 2014 07:40:11 GMT
Content-Type: text/css
Connection: keep-alive
Set-Cookie: __cfduid=d0cc5afd385060dd8ba26265f0ebf40f81399880411024; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.sstatic.net; HttpOnly
Cache-Control: public, max-age=604800
Last-Modified: Wed, 30 Apr 2014 22:09:37 GMT
ETag: "8026e7dfc064cf1:0"
Vary: Accept-Encoding
CF-Cache-Status: HIT
Expires: Mon, 19 May 2014 07:40:11 GMT
CF-RAY: 1294f778e75d04a3-CDG
Notez qu'il n'y a pas de corps et que la réponse est un 4 non modifié . Cela indique au client que le contenu qu'il a déjà (dans le cache local) pour cette URL est toujours frais.
Cela ne veut pas dire que c'est le scénario optimal. L'utilisation d'outils tels que l'onglet réseau de chrome vous permet de voir exactement combien de temps et pour quoi faire, une demande prend:
Parce que la réponse n'a pas de corps, le temps de réponse sera beaucoup moins important car il y a moins de données à transférer. Mais il y a c'est toujours une réponse. et il y a est toujours tous les frais généraux de connexion au serveur distant.
S'il n'y a pas d'étags, pas de dernier en-tête modifié et seulement un en-tête expiré défini à l'avenir - seul le tout premier accès à une URL entraînera une communication avec le serveur distant. Il s'agit d'une bien connue? Meilleure pratique pour de meilleures performances frontales . Si tel est le cas, pour les demandes ultérieures, un client lira le contenu de son propre cache et ne communiquera pas du tout avec le serveur distant.
Cela présente des avantages de performance clairs, qui sont particulièrement importants sur les appareils mobiles où la latence peut être importante (pour le moins).
C'est pour contourner le cache d'un client que les sites utilisent un argument de requête. Lorsque le contenu change (ou si une nouvelle version du site est publiée) l'argument de requête est modifié, et donc une version nouveau de ce fichier sera demandée car l'url a changé. C'est moins de travail/plus pratique que de renommer le fichier à chaque fois qu'il change, ce n'est cependant pas sans ses problèmes,
L'utilisation de chaînes de requête empêche la mise en cache du proxy , dans la citation ci-dessous, l'auteur démontre qu'une demande du navigateur <-> serveur de cache de proxy <-> site Web n'utilise pas le cache de proxy:
Charger mylogo.gif? V = 1.2 deux fois (vider le cache entre les deux) entraîne les en-têtes suivants:
>> GET http://stevesouders.com/mylogo.gif?v=1.2 HTTP/1.1 << HTTP/1.0 200 OK << Date: Sat, 23 Aug 2008 00:19:34 GMT << Expires: Tue, 21 Aug 2018 00:19:34 GMT << X-Cache: MISS from someserver.com << X-Cache-Lookup: MISS from someserver.com >> GET http://stevesouders.com/mylogo.gif?v=1.2 HTTP/1.1 << HTTP/1.0 200 OK << Date: Sat, 23 Aug 2008 00:19:47 GMT << Expires: Tue, 21 Aug 2018 00:19:47 GMT << X-Cache: MISS from someserver.com << X-Cache-Lookup: MISS from someserver.com
Ici, il est clair que la deuxième réponse n'a pas été servie par le proxy: les en-têtes de réponse de mise en cache disent MISS, les valeurs de date et d'expiration changent, et la queue du journal d'accès stevesouders.com affiche deux résultats.
Cela ne doit pas être pris à la légère - lorsque l'accès à un site Web situé physiquement à l'autre bout du monde, les temps de réponse peuvent être très lents. Obtenir une réponse d'un serveur proxy situé le long de l'itinéraire peut faire la différence entre un site Web utilisable ou non - dans le cas de ressources mises en cache pour toujours, cela signifie que le premier chargement d'une URL est lent, dans le cas de l'utilisation de demandes de validation, il signifie que l'ensemble du site sera lent.
La "meilleure" solution consiste à créer des fichiers de contrôle de version de sorte que chaque fois que le contenu change, l'URL change également. Normalement, cela serait automatisé dans le cadre du processus de génération.
Cependant, un quasi-compromis est d'implémenter une règle de réécriture comme
# ------------------------------------------------------------------------------
# | Filename-based cache busting |
# ------------------------------------------------------------------------------
# If you're not using a build process to manage your filename version revving,
# you might want to consider enabling the following directives to route all
# requests such as `/css/style.12345.css` to `/css/style.css`.
# To understand why this is important and a better idea than `*.css?v231`, read:
# http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L]
</IfModule>
De cette façon, une demande de foo.123.css
est traité par le serveur comme foo.css
- cela a tous les avantages d'utiliser un paramètre de requête pour le contournement du cache, mais sans le problème de la désactivation de la mise en cache du proxy.
L'en-tête Last-Modified est appliqué différemment d'un navigateur à l'autre, mais généralement le navigateur émet une demande GET conditionnelle à laquelle le serveur doit répondre si le cache doit être mis à jour. Par exemple, dans Firefox ...
L'en-tête de réponse "Last-Modified" peut être utilisé comme un validateur faible. Il est considéré comme faible car il n'a qu'une résolution d'une seconde. Si l'en-tête "Last-Modified" est présent dans une réponse, le client peut émettre un en-tête de demande "If-Modified-Since" pour valider le document mis en cache.
Lorsqu'une demande de validation est effectuée, le serveur peut soit ignorer la demande de validation et la réponse avec un 200 OK normal, soit renvoyer 304 Non modifié pour demander au navigateur d'utiliser sa copie en cache. Cette dernière réponse peut également inclure des en-têtes qui mettent à jour le délai d'expiration du document mis en cache.
En définissant un horodatage (ou une empreinte digitale), vous indiquez explicitement au navigateur quand il doit mettre à jour son cache et vous pouvez ensuite définir des délais d'expiration très longs.
Il convient de noter que la documentation sur le pipeline d'actifs Rails ( http://guides.rubyonrails.org/asset_pipeline.html ) cite 3 avantages pour les empreintes digitales sur un horodatage de chaîne de requête:
Pour plus de détails et les meilleures pratiques sur la mise en cache: https://developers.google.com/speed/docs/best-practices/caching