Vaut-il la peine de changer la structure complète de mon fichier d'images utilisateur pour profiter de la mise en cache simple du navigateur?


9

Sur l'un de mes sites mobiles, je stocke simplement les images de profil de mon utilisateur en tant que «1.jpg» dans leur dossier utilisateur, et j'y vais progressivement pour toutes les photos supplémentaires qu'ils téléchargent. Cela signifie que chaque fois qu'ils changent leur image de profil, par exemple, le nom de fichier reste le même.

J'ai voulu profiter de la mise en cache des images pour que la même vieille image ne soit pas téléchargée maintes et maintes fois lorsque le profil d'un utilisateur est consulté et revu, mais en même temps, je veux que les navigateurs de mes utilisateurs téléchargez le nouveau s'il a changé.

D'après ce que j'ai lu, il semble que la seule façon de vraiment le faire est d'utiliser réellement des noms de fichiers aléatoires et de garder une trace de tous ces noms de fichiers dans la base de données, afin que vous puissiez définir un cache qui n'expire pas, alors que récemment -les photos modifiées sont tirées à nouveau car elles ont un nouveau nom de fichier. La beauté de la façon dont je les ai structurés jusqu'à présent, cependant, est que je peux ignorer complètement la base de données et accéder directement aux fichiers car leur emplacement est prévisible.

Ma question est donc la suivante: cela vaut-il la peine que je modifie la structure complète des fichiers de mon site, en plus d'ajouter l'élément DB, au profit de la mise en cache éternelle et du re-téléchargement automatique lors d'un nouveau téléchargement?

C'est une entreprise énorme, mais si elle est jugée digne, je n'ai aucun problème à aller de l'avant avec ce changement radical. Je veux juste m'assurer que c'est comme ça que les "grands garçons" le font pour que je n'ai plus jamais à changer la structure des fichiers.

Merci.

Réponses:


7

Une solution couramment utilisée consiste à faire en sorte que les URL de vos images ressemblent à ceci:

http://www.example.com/path/to/images/1.jpg?v=123456

Ici, /path/to/images/1.jpgest le chemin URL réel de l'image, alors qu'il ne ?v=123456s'agit que d'une requête factice fixant la fin de l'URL. La chaîne de requête peut être n'importe quoi - un numéro de version, un horodatage, un hachage du contenu de l'image - tant que vous la changez chaque fois que l'image change, et la gardez la même quand elle ne change pas.

L'astuce est que le serveur Web, lorsqu'on lui demande de servir une telle URL, ignorera la chaîne de requête, car l'URL pointe en fait vers un fichier statique. Mais pour le navigateur de l'utilisateur (et pour tout proxy entre les deux), les URL avec différentes chaînes de requête seront complètement différentes, et donc toute modification de la chaîne de requête force le navigateur à recharger le fichier.

Ainsi, vous pouvez configurer votre serveur Web pour envoyer Expireset Cache-Controldes en-têtes HTTP pour permettre la mise en cache indéfinie, en sachant que vous pouvez forcer un rechargement en modifiant la chaîne de requête. Une façon de le faire, si vous utilisez Apache avec mod_expires , est de mettre un .htaccessfichier dans votre répertoire d'images avec les lignes:

ExpiresActive On
ExpiresDefault "access plus 1 year"

Cette technique est utilisée par de nombreux sites Web populaires. Par exemple, si vous regardez la source HTML de cette même page, vous constaterez que la feuille de style est chargée à partir d'une URL comme celle-ci:

http://cdn.sstatic.net/stackoverflow/all.css?v=7cd8ea9d6f1e

Ici, le ?v=7cd8ea9d6f1eest une chaîne de requête factice comme je l'ai décrit ci-dessus; vous pouvez le confirmer en le modifiant et en voyant qu'il renvoie en effet toujours le même fichier.


Aussi intéressant, mais comment pourrais-je garder une trace de la dernière modification du fichier par rapport à la première consultation du navigateur, afin de déterminer quand je devrais dire au navigateur de l'utilisateur de le récupérer à nouveau (par exemple en changeant la valeur de la requête)?
ProgrammerGirl

1
Vous n'avez pas besoin de suivre le moment où le fichier a été consulté. Gardez simplement une trace de la dernière modification du fichier (ou d'une autre propriété appropriée) et incluez-le dans la chaîne de requête. De cette façon, chaque fois que le fichier change, l'URL change également.
Ilmari Karonen

Très, très, intéressant. Je pourrais donc vraisemblablement récupérer la propriété "last modified" des fichiers, et juste en faire la valeur de la requête, n'est-ce pas?
ProgrammerGirl

1
Oui, cela devrait fonctionner.
Ilmari Karonen

1
Il n'y a pas d'inconvénients importants à ma connaissance. Vous pourriez vous retrouver avec des copies en double de vos images dans les index des moteurs de recherche, mais au moins les principaux moteurs de recherche comme Google sont assez intelligents pour gérer de telles choses, car c'est une astuce courante. Dans tous les cas, ce problème peut être atténué en envoyant des en-têtes HTTP rel = "canonical" et en gardant vos délais d'expiration modestes (disons juste un mois ou une semaine au lieu d'une année entière).
Ilmari Karonen

6

Il existe plusieurs façons de mettre en cache.

GET conditionnel

Si vous stockez ces images sur le système de fichiers et les diffusez directement via le serveur Web, vous utilisez probablement déjà le get conditionnel . Le serveur Web utilisera automatiquement les métadonnées du système de fichiers pour définir un en-tête ETAG et répondra automatiquement par «304 non modifié» si le navigateur inclut If-Modified-Sinceou en- If-Matchestêtes dans sa demande. (Tous les navigateurs le feront.)

Dans ce cas, l'image entière n'est pas renvoyée, vous économisez donc de la bande passante. Cependant, une demande GET sera toujours émise, vous aurez donc la surcharge et la latence d'une demande.

Vous pouvez diminuer légèrement le nombre de demandes au détriment de la fraîcheur du cache en ayant votre serveur Web défini des en- Cache-Controltêtes avec une public,max-age=Nvaleur pour vos images. Cela signifie que les caches peuvent conserver la ressource pendant au plus max-agesecondes avant de devoir vérifier si elle est mise à jour.

Cependant, HTTP définit une seule façon d'invalider une entrée de cache, qui peut ne pas correspondre à la sémantique de votre application: si vous POSTEZ ou METTEZ sur une URL qui met à jour la photo de profil, répondez avec un en- Location: [url of photo]tête et l'entrée de cache pour cette URL sera invalidée.

(Il s'agit du mécanisme qui vous permet de mettre en cache une page Web avec des commentaires, puis de recharger la page de force par le navigateur après que l'utilisateur a publié un nouveau commentaire. Le navigateur répondrait à un POST /commentavec 303 See Otheret un Location: /page/with/comment. Notez que cela n'a pas été utilisé pour fonctionner dans Firefox en raison d'un bug de longue date .)

À moins que vous n'ayez beaucoup de trafic, cette approche de la mise en cache convient.

Changer les URL

Une URL est une représentation d'une ressource, donc une autre façon de gérer la mise en cache n'est pas de changer les paramètres de cache pour la ressource, mais de créer une nouvelle ressource avec une directive "cache forever". C'est l'approche privilégiée par les "grands garçons", car elle leur permet de ne générer aucune demande supplémentaire, leur permettant d' économiser beaucoup de bande passante. L'inconvénient est qu'il nécessite une comptabilité supplémentaire.

Il existe deux techniques générales pour cela.

Chaînes de requête

Les serveurs Web ignorent les chaînes de requête lorsqu'ils servent un fichier à partir du système de fichiers. Caches, cependant, ne le font pas: /1.jpg?t=12345et /1.jpg?t=67890sont deux complètement différentes, sans rapport avec les ressources, même si le serveur pense qu'ils sont les mêmes.

Donc, une chose simple que vous pouvez faire est d'ajouter l'horodatage du système de fichiers en tant que chaîne de requête chaque fois que vous faites référence à une ressource dans votre html et définissez un en- Expirestête long . Le navigateur mettra alors en cache cette ressource pour toujours et n'effectuera aucun GET tant que la chaîne de requête ne changera pas.

Un inconvénient est qu'il est difficile, voire impossible, d'indiquer au serveur Web la nouvelle URL d'un élément si vous souhaitez invalider de force un cache. Par exemple, si un navigateur a une page HTML en cache avec une /1.jpg?v=1référence, mais qu'il est arrivé d'effacer l'entrée /1.jpg?v=1(peut-être qu'il manquait d'espace de fichier ou de mémoire), il fera une nouvelle demande à /1.jpg?v=1. Si entre-temps l'image a changé en /1.jpg?v=2, la bonne réponse est soit:

  1. Servir l'ancienne version du fichier. Vous feriez cela si vous vouliez que toutes les ressources soient cohérentes les unes par rapport aux autres à un certain moment. C'est ce que vous devez faire avec les fichiers CSS, par exemple, car un nouveau fichier css avec un ancien fichier html peut ne pas fonctionner correctement!
  2. Redirigez vers la nouvelle version du fichier à l'aide de 301 Moved Permanently. Vous feriez cela si vous vouliez que toutes les ressources soient aussi nouvelles que possible.

Les deux sont difficiles à faire avec un serveur Web seul, ce qui signifie que vous devez appeler une application Web même pour les demandes d'images, ce qui peut être à la fois plus compliqué et plus gourmand en ressources. Les serveurs Web sont très rapides à servir des fichiers, donc la surcharge d'une application Web peut finir par avaler vos gains de bande passante et de latence.

Noms de fichiers

Au lieu d'ajouter une chaîne de requête, vous modifiez le nom de fichier. Cela signifie qu'il est facile de conserver plusieurs versions de fichiers sur le système de fichiers, mais vous aurez probablement besoin de stocker les métadonnées de fichiers et de tenir d'autres registres de base de données pour garder une trace de vos ressources et de leurs noms.


0

Pour en savoir plus sur le statut http 304 Not Modified, vous devriez pouvoir répondre à une demande de téléchargement avec 304, et dire au serveur d’utiliser les données mises en cache, au lieu de les renvoyer au navigateur. et lisez cette question /programming/2978496/make-php-page-return-304-not-modified-if-it-hasnt-been-modified


Intéressant, mais s'agit-il d'une solution de «pansement» à un schéma de fichier problématique, ou mon schéma de fichier est-il bon et a juste besoin de cette capacité de mise en cache? De plus, comment pourrais-je savoir quand le fichier a été modifié pour la dernière fois par rapport à la première consultation du navigateur, afin de déterminer quand je devrais demander au navigateur de l'utilisateur de le récupérer à nouveau?
ProgrammerGirl

je ne suis pas si familier avec ça, pense que Francis Avila en sait beaucoup plus à ce sujet
Puggan Se
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.