Éviter les requêtes réseau inutiles avec le cache HTTP

La récupération de ressources sur le réseau est à la fois lente et coûteuse:

  • Les réponses volumineuses nécessitent de nombreux allers-retours entre le navigateur et le serveur.
  • Votre page ne se chargera que lorsque toutes ses ressources critiques auront été entièrement téléchargées.
  • Si une personne accède à votre site avec un forfait Internet limité, chaque demande inutile sur le réseau est un gaspillage.

Comment éviter les requêtes réseau inutiles ? Le cache HTTP du navigateur constitue votre première ligne de défense. Cette approche n'est pas forcément la plus puissante ou la plus flexible, et vous disposez d'un contrôle limité sur la durée de vie des réponses mises en cache, mais elle est efficace, compatible avec tous les navigateurs et ne demande pas beaucoup de travail.

Ce guide présente les principes de base d'une implémentation efficace de la mise en cache HTTP.

Compatibilité du navigateur

Il n’existe pas réellement d’API unique appelée le cache HTTP. C'est le nom général d'un ensemble d'API de plate-forme Web. Ces API sont compatibles avec tous les navigateurs:

Cache-Control

Navigateurs pris en charge

  • Vrai
  • 12
  • Vrai
  • Vrai

Source

ETag

Navigateurs pris en charge

  • Vrai
  • 12
  • Vrai
  • Vrai

Source

Last-Modified

Navigateurs pris en charge

  • Vrai
  • 12
  • Vrai
  • Vrai

Source

Fonctionnement du cache HTTP

Toutes les requêtes HTTP effectuées par le navigateur sont d'abord acheminées vers le cache du navigateur afin de vérifier si une réponse valide mise en cache peut être utilisée pour traiter la requête. En cas de correspondance, la réponse est lue à partir du cache, ce qui élimine à la fois la latence du réseau et les coûts liés aux données induits par le transfert.

Le comportement du cache HTTP est contrôlé par une combinaison d'en-têtes de requête et d'en-têtes de réponse. Dans l'idéal, vous pourrez contrôler à la fois le code de votre application Web (qui déterminera les en-têtes de requête) et la configuration de votre serveur Web (qui déterminera les en-têtes de réponse).

Reportez-vous à l'article Mise en cache HTTP de MDN pour obtenir une présentation conceptuelle plus approfondie.

En-têtes de requête: conservez les valeurs par défaut (généralement)

Vous devez inclure un certain nombre d'en-têtes importants dans les requêtes sortantes de votre application Web, mais le navigateur se charge presque toujours de les définir à votre place lorsqu'il effectue des requêtes. Les en-têtes de requête qui affectent la vérification de l'actualisation, tels que If-None-Match et If-Modified-Since, s'affichent si le navigateur comprend les valeurs actuelles du cache HTTP.

C'est une bonne nouvelle : cela signifie que vous pouvez continuer à inclure des balises telles que <img src="my-image.png"> dans votre code HTML. Le navigateur se charge alors automatiquement de la mise en cache HTTP, sans effort supplémentaire.

En-têtes de réponse: configurer votre serveur Web

La partie la plus importante de la configuration de la mise en cache HTTP est les en-têtes que votre serveur Web ajoute à chaque réponse sortante. Les en-têtes suivants sont tous pris en compte pour le comportement de mise en cache efficace:

  • Cache-Control. Le serveur peut renvoyer une instruction Cache-Control pour spécifier comment et pendant combien de temps le navigateur et les autres caches intermédiaires doivent mettre en cache la réponse individuelle.
  • ETag : lorsque le navigateur trouve une réponse mise en cache expirée, il peut envoyer un petit jeton (généralement un hachage du contenu du fichier) au serveur pour vérifier si le fichier a été modifié. Si le serveur renvoie le même jeton, le fichier est identique. Il n'est donc pas nécessaire de le télécharger à nouveau.
  • Last-Modified. Cet en-tête a la même fonction que ETag, mais il utilise une stratégie temporelle pour déterminer si une ressource a été modifiée, par opposition à la stratégie basée sur le contenu de ETag.

Certains serveurs Web intègrent la prise en charge de la définition de ces en-têtes par défaut, tandis que d'autres les omettent complètement, à moins que vous ne les configuriez explicitement. Les détails spécifiques à la configuration des en-têtes varient considérablement selon le serveur Web que vous utilisez. Nous vous conseillons de consulter la documentation de votre serveur pour obtenir les informations les plus précises.

Pour vous faciliter la tâche, voici des instructions concernant la configuration de quelques serveurs Web courants:

L'omission de l'en-tête de réponse Cache-Control ne désactive pas la mise en cache HTTP. Au lieu de cela, les navigateurs déterminent avec efficacité quel type de comportement de mise en cache est le plus logique pour un type de contenu donné. Il y a de fortes chances que vous souhaitiez avoir plus de contrôle que cela, alors prenez le temps de configurer vos en-têtes de réponse.

Quelles valeurs d'en-tête de réponse devez-vous utiliser ?

Deux scénarios importants sont à prendre en compte lors de la configuration des en-têtes de réponse de votre serveur Web.

Mise en cache de longue durée pour les URL avec gestion des versions

Comment les URL avec gestion des versions peuvent-elles améliorer votre stratégie de mise en cache ?
Les URL avec versions gérées sont une bonne pratique, car elles facilitent l'invalidation des réponses mises en cache.

Supposons que votre serveur demande aux navigateurs de mettre en cache un fichier CSS pendant un an (Cache-Control: max-age=31536000), mais que votre concepteur vient d'effectuer une mise à jour d'urgence que vous devez déployer immédiatement. Comment demander aux navigateurs de mettre à jour la copie en cache "obsolète" du fichier ? Ce n'est pas possible, du moins pas sans modifier l'URL de la ressource.

Une fois la réponse mise en cache par le navigateur, la version mise en cache est utilisée jusqu'à ce qu'elle ne soit plus à jour, comme déterminé par max-age ou expires, ou jusqu'à ce qu'elle soit évincée du cache pour une autre raison, par exemple lorsque l'utilisateur vide le cache de son navigateur. Par conséquent, différents utilisateurs peuvent finir par utiliser différentes versions du fichier lors de la création de la page: ceux qui viennent de récupérer la ressource utilisent la nouvelle version, tandis que ceux qui ont mis en cache une copie antérieure (mais toujours valide) utilisent une version plus ancienne de sa réponse.

Comment bénéficier du meilleur des deux mondes: mise en cache côté client et mises à jour rapides ? Vous modifiez l'URL de la ressource et forcez l'utilisateur à télécharger la nouvelle réponse chaque fois que son contenu est modifié. Pour ce faire, vous devez généralement intégrer une empreinte du fichier ou un numéro de version dans son nom de fichier (par exemple, style.x234dff.css).

Lorsque vous répondez aux demandes d'URL qui contiennent une empreinte ou des informations de gestion des versions, et dont le contenu n'est jamais censé changer, ajoutez Cache-Control: max-age=31536000 à vos réponses.

Cette valeur indique au navigateur que lorsqu'il doit charger la même URL à n'importe quel moment au cours de l'année suivante (31 536 000 secondes, soit la valeur maximale acceptée), il peut immédiatement utiliser la valeur contenue dans le cache HTTP, sans avoir à envoyer de requête réseau à votre serveur Web. C'est super ! Vous avez immédiatement gagné en fiabilité et en vitesse en évitant le réseau !

Les outils de création tels que webpack peuvent automatiser le processus d'attribution des empreintes de hachage aux URL de vos éléments.

Nouvelle validation du serveur pour les URL dont la version n'est pas définie

Malheureusement, les URL que vous chargez ne sont pas toutes gérées par version. Il se peut que vous ne puissiez pas inclure d'étape de compilation avant de déployer votre application Web. Vous ne pouvez donc pas ajouter de hachages à vos URL d'élément. Par ailleurs, chaque application Web a besoin de fichiers HTML. Ces fichiers n'incluront (presque !) aucune information de gestion des versions, car personne ne se préoccupera d'utiliser votre application Web s'il a besoin de se souvenir que l'URL à consulter est https://example.com/index.34def12.html. Que pouvez-vous faire pour ces URL ?

C'est un scénario dans lequel vous devez admettre la victoire. La mise en cache HTTP seule n'est pas assez puissante pour éviter complètement le réseau. (Ne vous inquiétez pas, vous découvrirez bientôt les service workers, qui nous apporteront toute l'assistance dont nous avons besoin pour faire revenir la bataille en votre faveur.) Mais il existe quelques mesures que vous pouvez prendre pour vous assurer que les requêtes réseau sont aussi rapides et efficaces que possible.

Les valeurs Cache-Control suivantes peuvent vous aider à ajuster l'emplacement et le mode de mise en cache des URL sans version:

  • no-cache : indique au navigateur qu'il doit être revalidé avec le serveur à chaque fois avant d'utiliser une version mise en cache de l'URL.
  • no-store : indique au navigateur et aux autres caches intermédiaires (tels que les CDN) de ne jamais stocker de version du fichier.
  • private. Les navigateurs peuvent mettre le fichier en cache, mais pas les caches intermédiaires.
  • public : la réponse peut être stockée par n'importe quel cache.

Consultez l'annexe: organigramme de Cache-Control pour visualiser le processus de décision des valeurs Cache-Control à utiliser. Cache-Control peut également accepter une liste d'instructions séparées par une virgule. Consultez l'annexe: exemples de Cache-Control.

Il peut également être utile de définir ETag ou Last-Modified. Comme indiqué dans la section En-têtes de réponse, ETag et Last-Modified ont tous deux le même objectif: déterminer si le navigateur doit télécharger de nouveau un fichier mis en cache qui a expiré. Nous vous recommandons d'utiliser ETag, car il est plus précis.

Exemple d'ETag

Supposons que 120 secondes se sont écoulées depuis la récupération initiale et que le navigateur a lancé une nouvelle requête pour la même ressource. Le navigateur commence par vérifier le cache HTTP et trouve la réponse précédente. Malheureusement, le navigateur ne peut pas utiliser la réponse précédente, car celle-ci a expiré. À ce stade, le navigateur peut envoyer une nouvelle requête et extraire la nouvelle réponse complète. Toutefois, cette méthode est inefficace, car si la ressource n'a pas changé, il n'y a aucune raison de télécharger les informations déjà présentes dans le cache.

C'est le problème que les jetons de validation, comme spécifié dans l'en-tête ETag, sont conçus pour résoudre. Le serveur génère et renvoie un jeton arbitraire, qui est généralement un hachage ou une autre empreinte du contenu du fichier. Le navigateur n'a pas besoin de savoir comment l'empreinte est générée. Il lui suffit de l'envoyer au serveur lors de la prochaine requête. Si l'empreinte est toujours la même, cela signifie que la ressource n'a pas changé et que le navigateur peut ignorer le téléchargement.

Si vous définissez ETag ou Last-Modified, la requête de revalidation est beaucoup plus efficace en lui permettant de déclencher les en-têtes de requête If-Modified-Since ou If-None-Match mentionnés dans En-têtes de requête.

Lorsqu'un serveur Web correctement configuré voit ces en-têtes de requêtes entrantes, il peut confirmer que la version de la ressource déjà présente dans le cache HTTP du navigateur correspond à la dernière version disponible sur le serveur Web. Si une correspondance est trouvée, le serveur peut répondre avec une réponse HTTP 304 Not Modified, ce qui équivaut à "Hey, continue d'utiliser ce que vous avez déjà !" Il y a très peu de données à transférer lors de l'envoi de ce type de réponse. Il est donc généralement beaucoup plus rapide que de devoir renvoyer une copie de la ressource réelle demandée.

Représentation visuelle d&#39;un client demandant une ressource et du serveur répondant avec un en-tête 304.
Le navigateur demande /file au serveur et inclut l'en-tête If-None-Match pour indiquer au serveur de ne renvoyer le fichier complet que si l'ETag du fichier sur le serveur ne correspond pas à la valeur If-None-Match du navigateur. Dans le cas présent, les deux valeurs correspondent. Le serveur renvoie donc une réponse 304 Not Modified avec des instructions sur la durée pendant laquelle le fichier doit être mis en cache (Cache-Control: max-age=120).

Résumé

Le cache HTTP est un moyen efficace d'améliorer les performances de chargement, car il réduit les requêtes réseau inutiles. Elle est compatible avec tous les navigateurs et nécessite très peu de travail de configuration.

Les configurations Cache-Control suivantes constituent un bon début:

  • Cache-Control: no-cache pour les ressources qui doivent être revalidées avec le serveur avant chaque utilisation.
  • Cache-Control: no-store pour les ressources qui ne doivent jamais être mises en cache.
  • Cache-Control: max-age=31536000 pour les ressources avec gestion des versions

L'en-tête ETag ou Last-Modified peut vous aider à revalider plus efficacement les ressources de cache expirées.

En savoir plus

Si vous souhaitez approfondir l'utilisation de l'en-tête Cache-Control, consultez le guide Bonnes pratiques de mise en cache et pièges à l'âge maximal de Jake Archibld.

Consultez la section Examiner votre cache pour savoir comment optimiser l'utilisation du cache pour les visiteurs connus.

Annexe: Autres conseils

Si vous avez plus de temps, voici d'autres moyens d'optimiser votre utilisation du cache HTTP:

  • Utilisez des URL cohérentes. Si vous affichez le même contenu sur des URL différentes, ce contenu sera récupéré et stocké plusieurs fois.
  • Minimisez la perte d'utilisateurs. Si une partie d'une ressource (un fichier CSS, par exemple) est fréquemment mise à jour, alors que ce n'est pas le cas du reste du fichier (comme le code de la bibliothèque), envisagez de diviser le code fréquemment mis à jour dans un fichier distinct et d'utiliser une stratégie de mise en cache de courte durée pour le code fréquemment mis à jour et une stratégie de mise en cache longue pour le code qui ne change pas souvent.
  • Consultez la nouvelle directive stale-while-revalidate si votre règle Cache-Control accepte un certain degré d'obsolescence.

Annexe: Organigramme du Cache-Control

Organigramme
Processus décisionnel pour la définition de vos en-têtes Cache-Control.

Annexe: exemples Cache-Control

Valeur Cache-Control Explication
max-age=86400 La réponse peut être mise en cache par les navigateurs et les caches intermédiaires pendant une durée maximale d'un jour (60 secondes x 60 minutes x 24 heures).
private, max-age=600 La réponse peut être mise en cache par le navigateur (mais pas par les caches intermédiaires) pendant 10 minutes maximum (60 secondes x 10 minutes).
public, max-age=31536000 La réponse peut être stockée par n'importe quel cache pendant un an.
no-store La réponse ne peut pas être mise en cache et doit être récupérée intégralement à chaque requête.