web-dev-qa-db-fra.com

Arrêtez le navigateur pour faire des requêtes HTTP pour les images qui doivent rester en cache - mod_expires

Après avoir lu de nombreux articles et posé quelques questions, j'ai finalement réussi à activer le code Apache mod_expires pour indiquer au navigateur qu'il DOIT mettre les images en mémoire cache pendant un an}.

<filesMatch "\.(ico|gif|jpg|png)$">
  ExpiresActive On
  ExpiresDefault "access plus 1 year"
  Header append Cache-Control "public"
</filesMatch>

Et heureusement, les réponses du serveur semblent être correctes:

HTTP/1.1 200 OK 
Date: Fri, 06 Apr 2012 19:25:30 GMT 
Server: Apache 
Last-Modified: Tue, 26 Jul 2011 18:50:14 GMT 
Accept-Ranges: bytes 
Content-Length: 24884 
Cache-Control: max-age=31536000, public 
Expires: Sat, 06 Apr 2013 19:25:30 GMT
Connection: close
Content-Type: image/jpeg 

Eh bien, je pensais que cela empêcherait le navigateur de télécharger et même de demander au serveur les images pendant un an. Mais c'est partiellement vrai: cause si vous fermez et rouvrez le navigateur, le navigateur ne télécharge plus les images} depuis le serveur, mais le navigateur demande toujours au serveur une requête HTTP pour chaque image} .

Comment forcer le navigateur à cesser de créer des requêtes HTTP pour chaque image? Même si ces requêtes HTTP ne sont pas suivies par une image en cours de téléchargement, il s'agit toujours de requêtes adressées au serveur} qui augmente inutilement la latence et ralentit rendu de page!

J'ai déjà dit au navigateur qu'il DOIT garder les images en cache pendant 1 an! Pourquoi le navigateur interroge-t-il toujours le serveur pour chaque image (même s'il ne télécharge pas l'image)?!


En regardant les graphiques de réseau dans FireBug (menu FireBug> Net> Images), je peux voir différents comportements de mise en cache (j'ai évidemment commencé avec le cache du navigateur complètement vide, j'ai forcé une suppression de cache sur le navigateur en utilisant "Effacer tout l'historique"):

  • _ {Lorsque la page est chargée pour la 1ère fois, toutes les images sont téléchargées} (il en va de même si je force un rechargement de page en cliquant sur le bouton de rechargement de page du navigateur). Cela a du sens!

  • Lorsque je navigue sur le site et que je reviens à la même page les images ne sont pas téléchargées du tout et le le navigateur n'interroge PAS même le serveur pour les images. Cela a du sens (et j'aimerais voir ce comportement aussi lorsque le navigateur est fermé)! 

  • Lorsque je ferme le navigateur et que je l'ouvre à nouveau sur la même page, le navigateur idiot envoie de toute façon une requête HTTP au serveur une fois par image: il ne télécharge PAS l'image, mais il émet tout de même une requête HTTP. navigateur interroge le serveur sur l’image} _ (le serveur répond avec 200 OK). C'est celui qui m'irrite! 

Je joins également les graphiques ci-dessous si vous êtes intéressé:

enter image description here

enter image description here

EDIT: vient d’être testé aussi avec FireFox 11.0 juste pour s’assurer que mon problème avec FireFox 3.6 n’était pas trop ancien. La même chose arrive !!! J'ai également testé le site Google et le site Stackoverflow}, ils envoient tous les deux le Cache-Control: max-age=... mais le navigateur envoie toujours une requête HTTP au serveur pour chaque image une fois le navigateur fermé et ouvert à nouveau sur la même page., après la réponse du serveur, le navigateur ne télécharge PAS l’image (comme je l’ai expliqué ci-dessus), mais il continue de faire la fichue requête qui augmente le temps nécessaire pour voir la page.

EDIT2: et supprimer l'en-tête Last-Modified comme suggéré ici ne résout pas le problème, cela ne fait aucune différence.

44
Marco Demaio

Vous utilisiez le mauvais outil pour analyser les demandes.

Je recommanderais le très utile addon Firefox En-têtes HTTP en direct afin que vous puissiez voir ce qui se passe réellement sur le réseau.

Et juste pour être sûr, vous pouvez ssh/PuTTY votre serveur et faire quelque chose comme 

tail -f /var/log/Apache2/access.log
14
Oliver Kurmis

Le comportement que vous voyez est le comportement prévu (voir RFC7234 pour plus de détails), spécifié: 

Tous les navigateurs modernes enverront des requêtes HTTP au serveur pour chaque élément de page affiché, quel que soit l'état du cache. Cette décision a été prise à la demande des services Web (notamment des réseaux de publicité) pour que les serveurs HTTP puissent conserver des enregistrements de chaque affichage de chaque élément. 

Si les navigateurs ne faisaient pas ces demandes, le serveur ne serait jamais averti qu'une image avait été affichée à l'utilisateur. Pour les réseaux de publicité, cela serait catastrophique. Dès le début, les réseaux de publicité ont «piraté» leur problème en diffusant la même image d'annonce en utilisant des noms générés aléatoirement (ex: 'coke_ad_1_98719283719283.gif'). Toutefois, pour les fournisseurs de services Internet, cette pratique entraînait une augmentation considérable du nombre de transferts de données, car chacun de leurs utilisateurs re-téléchargeait ces images d'annonce identiques en contournant tous les serveurs de mise en cache/proxy de leur fournisseur d'accès.

Une trêve est donc atteinte: les navigateurs envoient toujours des requêtes HTTP, même pour les éléments en cache non expirés. Les serveurs répondraient avec les codes d’état HTTP 304 ("non modifiés"). Cela permet aux serveurs d’enregistrer le fait que l’image a été affichée sur le client. En conséquence, les réseaux publicitaires généralement ont cessé d'utiliser des noms d'images aléatoires pour contourner les serveurs de cache réseau.

Cela a donné aux réseaux publicitaires ce qu’ils voulaient - un enregistrement de chaque image affichée - et aux fournisseurs d’accès Internet ce qu’ils voulaient - des images pouvant être mises en cache et du contenu statique.

C'est pourquoi vous ne pouvez pas faire grand-chose pour empêcher les navigateurs d'envoyer des requêtes HTTP pour les éléments de page en cache.

Mais si vous regardez les autres solutions côté client disponibles fournies avec html5, il existe une possibilité d'empêcher le chargement des ressources.

  1. Cache Manifest (malgré ses pièges)
  2. IndexedDB (Nice asynchronous features, permet le stockage d'objets blob)
  3. Stockage local (pas asynchrone)
27
Jason Buberel

Il y a une différence entre "recharger" et "rafraîchir". Le simple fait de naviguer vers une page avec des boutons Précédent/Suivant ne génère généralement pas de nouvelles requêtes HTTP, mais si vous appuyez spécifiquement sur F5 pour "rafraîchir" la page, le navigateur revérifie son cache. Cela dépend du navigateur, mais semble être la norme pour FF et Chrome (c’est-à-dire les navigateurs qui ont la possibilité de surveiller facilement leur trafic réseau.) Appuyez sur F6, entrez devrait mettre en évidence la barre d’adresses URL puis «y accéder», ce qui devrait Rechargez la page mais ne vérifiez pas les ressources de la page.

Update: clarification du comportement de navigation en arrière et en avant. Cela s'appelle "Back Forward Cache" ou BFCache dans les navigateurs. Lorsque vous naviguez avec les boutons Précédent/Suivant, l’intention est de vous montrer exactement ce que la page était lorsque vous l’aviez vue dans votre propre scénario. Aucune demande de serveur n’est faite lorsqu’on utilise les transferts en arrière, même si l’en-tête du cache du serveur indique l’expiration d’un élément particulier.

Si vous voyez (200 OK BFCache) dans le panneau de votre réseau de développeurs, le serveur n’a jamais été touché - même pour demander s’il a été modifié depuis.

http://www.softwareishard.com/blog/firebug/firebug-tip-what-the-heck-is-bfcache/

11
chugadie

Si je force une actualisation à l'aide de F5 ou F5 + Ctrl, une demande est envoyée. Cependant, si je ferme le navigateur et saisis à nouveau l'URL, NO reqeust n'est pas envoyé. La façon dont j'ai testé si une requête est envoyée ou non consistait à utiliser des points d'arrêt sur la requête begin sur le serveur, même si une requête n'était pas envoyée, il apparaît toujours dans Firebug comme ayant attendu 7 ms, alors méfiez-vous de cela.

7
Peter Lundsby

Ce que vous décrivez ici ne reflète pas mon expérience. Si le contenu est servi avec une directive no-store ou si vous effectuez une actualisation explicite, eh bien, je m'attendrais à ce qu'il retourne au serveur Origin, sinon il devrait être mis en cache lors du redémarrage du navigateur (en supposant qu'il soit autorisé un fichier cache).

En regardant vos cascades avec un peu plus de détails (ce qui est délicat parce qu'elles sont un peu petites et floues), le navigateur semble faire exactement ce qu'il devrait - il a entrées pour les images - mais elles ne font que charger depuis le cache local pas depuis le serveur d'origine - vérifiez l'en-tête "Date" dans la réponse (pourquoi pensez-vous que cela prend des millisecondes au lieu de quelques secondes?). C'est pourquoi ils sont colorés différemment.

6
symcbean

Après avoir passé beaucoup de temps à chercher une réponse raisonnable, j'ai trouvé le lien ci-dessous le plus utile et cela répond à la question posée ici.

https://webmasters.stackexchange.com/questions/25342/headers-to-prevent-304-if-modified-since-head-requests

4
dev-vb

Ce que vous voyez dans Chrome ne constitue pas un enregistrement des demandes HTTP réelles, mais un enregistrement des demandes d'actifs. Chrome fait cela pour vous montrer qu'un élément est en train d'être demandé par la page. Cependant, cette vue n'indique pas réellement si la demande est en cours. Si un actif est mis en cache, Chrome ne créera jamais la requête HTTP sous-jacente.

Vous pouvez également le confirmer en survolant les segments violets de la chronologie. Les ressources mises en cache auront un (from cache) dans l'info-bulle.

Pour voir les requêtes HTTP réelles, vous devez regarder à un niveau inférieur. Dans certains navigateurs, cela peut être fait avec un plugin (comme Live HTTP Headers).

En réalité, toutefois, pour vérifier que les demandes ne sont pas effectuées, vous devez vérifier les journaux de votre serveur ou utiliser un proxy de débogage tel que Charles ou Fiddler. Cela fonctionnera sur un niveau HTTP pour s'assurer que les demandes ne se produisent pas réellement.

0
wharding28

Cette question a une meilleure réponse ici sur le site d’échange de piles de webmasters.

Plus d'informations, également citées dans le lien ci-dessus, se trouvent sur httpwatch

Selon l'article:

Il existe plusieurs situations dans lesquelles Internet Explorer doit vérifier si une entrée en cache est valide:

  • L'entrée en cache n'a pas de date d'expiration et le contenu est en cours d'accès pour la première fois dans une session de navigateur.
  • L'entrée mise en cache a une date d'expiration mais elle a expiré
  • L'utilisateur a demandé une mise à jour de page en cliquant sur le bouton Actualiser ou en appuyant sur F5.

    entrez le code ici

0
sandeepkunkunuru

Validation du cache et réponse 304

Il existe plusieurs situations dans lesquelles Internet Explorer doit vérifier si une entrée en cache est valide:

  • L'entrée en cache n'a pas de date d'expiration et le contenu est en cours d'accès pour la première fois dans une session de navigateur.

  • L'entrée mise en cache a une date d'expiration mais elle a expiré

  • L'utilisateur a demandé une mise à jour de page en cliquant sur le bouton Actualiser ou en appuyant sur F5.

Si l'entrée en cache a une date de dernière modification, IE l'envoie dans l'en-tête If-Modified-Since d'un message de demande GET:

GET /images/logo.gif HTTP/1.1
Accept: */*
Referer: http://www.google.com/
Accept-Encoding: gzip, deflate
If-Modified-Since: Thu, 23 Sep 2004 17:42:04 GMT
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)
Host: www.google.com

Le serveur vérifie l'en-tête If-Modified-Since et répond en conséquence. Si le contenu n'a pas été modifié depuis la date/heure spécifiée, il répond avec un code d'état de 304 et un message de réponse contenant uniquement des en-têtes:

HTTP/1.1 304 Not Modified
Content-Type: text/html
Server: GWS/2.1
Content-Length: 0
Date: Thu, 04 Oct 2004 12:00:00 GMT

La réponse peut être rapidement téléchargée car elle ne contient aucun contenu et force IE à lire les données requises dans la mémoire cache. En réalité, cela ressemble à une redirection vers le cache du navigateur local.

Si l'objet demandé a réellement changé depuis la date/heure indiquée dans l'en-tête If-Modified-Since, le serveur répond avec un code d'état de 200 et fournit la version modifiée de la ressource.

0
Rakesh

S'il s'agit d'une question vitale ou mortelle (si vous voulez optimiser le chargement de page de cette façon ou si vous voulez réduire la charge sur le serveur autant que possible), alors il y a IS une solution de contournement .

Utilisez HTML5 local storage pour mettre en cache des images après leur première demande.

  • [+] Vous pouvez empêcher le navigateur d'envoyer des requêtes HTTP qui, dans 99% des cas, renverraient 304 (non modifié), quel que soit le résultat des tentatives de l'utilisateur (F5, ctrl + F5, nouvelle page, etc.).

  • [-] Vous devez déployer des efforts supplémentaires dans la prise en charge de javascript pour cela.

  • [-] Les images sont stockées en base64 (nous ne pouvons pas stocker de données binaires), c'est pourquoi elles sont décodées à chaque fois côté client. Ce qui est (généralement} _ assez rapide et pas grave, mais cela reste une utilisation supplémentaire du processeur du côté client et il convient de le garder à l’esprit.

  • [-] Le stockage local est limité. Vous pouvez viser à utiliser environ 5 Mo de données par domaine (Remarque: base64 ajoute environ 30% à la taille d'origine de l'image).

  • [?] Pris en charge par majorité des navigateurs. http://caniuse.com/#search=localstorage

Exemple

Test

0
djeendo