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 pas tant que toutes ses ressources critiques n'auront pas été entièrement téléchargées.
- Si une personne accède à votre site avec un forfait de données mobiles limité, chaque requête réseau inutile lui fait perdre de l'argent.
Comment éviter les requêtes réseau inutiles ? Le cache HTTP du navigateur est votre première ligne de défense. Ce n'est pas nécessairement l'approche la plus puissante ni la plus flexible, et vous n'avez qu'un contrôle limité sur la durée de vie des réponses mises en cache. Toutefois, elle est efficace, compatible avec tous les navigateurs et ne nécessite pas beaucoup de travail.
Ce guide vous présente les principes de base d'une mise en cache HTTP efficace.
Compatibilité du navigateur
Il n'existe pas d'API unique appelée "cache HTTP". Il s'agit du nom général d'un ensemble d'API de plate-forme Web. Ces API sont compatibles avec tous les navigateurs :
Cache-Control
ETag
Last-Modified
Fonctionnement du cache HTTP
Toutes les requêtes HTTP effectuées par le navigateur sont d'abord acheminées vers le cache du navigateur pour vérifier s'il existe une réponse valide mise en cache qui peut être utilisée pour répondre à la requête. Si une correspondance est trouvée, la réponse est lue à partir du cache, ce qui élimine à la fois la latence du réseau et les coûts de données liés au 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 contrôlez à la fois le code de votre application Web (qui détermine les en-têtes de requête) et la configuration de votre serveur Web (qui détermine les en-têtes de réponse).
Pour une présentation plus détaillée du concept, consultez l'article Mise en cache HTTP de MDN.
En-têtes de requête : conservez les valeurs par défaut (généralement)
Un certain nombre d'en-têtes importants doivent être inclus dans les requêtes sortantes de votre application Web, mais le navigateur se charge presque toujours de les définir en votre nom lorsqu'il effectue des requêtes. Les en-têtes de requête qui affectent la vérification de l'actualisation, comme If-None-Match et If-Modified-Since, s'affichent en fonction de la compréhension par le navigateur des valeurs actuelles dans le 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, et que le navigateur s'occupe automatiquement de la mise en cache HTTP pour vous, 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 l'en-tête que votre serveur Web ajoute à chaque réponse sortante. Les en-têtes suivants sont tous pris en compte dans le comportement de mise en cache effectif :
Cache-Control: le serveur peut renvoyer une directiveCache-Controlpour 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 qui a expiré, 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, cela signifie que le fichier est identique et qu'il n'est pas nécessaire de le télécharger à nouveau.Last-Modified. Cet en-tête a le même objectif queETag, mais utilise une stratégie basée sur le temps pour déterminer si une ressource a changé, contrairement à la stratégie basée sur le contenu deETag.
Certains serveurs Web sont compatibles de manière intégrée avec la définition de ces en-têtes par défaut, tandis que d'autres les omettent complètement, sauf si vous les configurez explicitement. La procédure de configuration des en-têtes varie considérablement en fonction du serveur Web que vous utilisez. Pour obtenir des informations plus précises, consultez la documentation de votre serveur.
Pour vous éviter de chercher, voici les instructions de configuration de quelques serveurs Web populaires :
L'omission de l'en-tête de réponse Cache-Control ne désactive pas la mise en cache HTTP. À la place, les navigateurs devinent le type de comportement de mise en cache le plus adapté à un type de contenu donné. Il est probable que vous souhaitiez un contrôle plus précis que celui proposé par cette option. Prenez donc le temps de configurer vos en-têtes de réponse.
Quelles valeurs d'en-tête de réponse devez-vous utiliser ?
Vous devez couvrir deux scénarios importants lorsque vous configurez les en-têtes de réponse de votre serveur Web.
Mise en cache de longue durée pour les URL avec versions gérées
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 indiquez-vous aux navigateurs de mettre à jour la copie mise en cache "obsolète" du fichier ? Vous ne pouvez pas, du moins pas sans modifier l'URL de la ressource.
Une fois que le navigateur a mis en cache la réponse, la version mise en cache est utilisée jusqu'à ce qu'elle ne soit plus actualisée, comme déterminé par max-age ou expires, ou jusqu'à ce qu'elle soit supprimée du cache pour une autre raison (par exemple, l'utilisateur vide le cache de son navigateur). Par conséquent, différents utilisateurs peuvent se retrouver à utiliser différentes versions du fichier lors de la construction de la page : les utilisateurs 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 profiter du meilleur des deux mondes : la mise en cache côté client et les 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 change. En règle générale, vous devez 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 à des requêtes d'URL contenant 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.
En définissant cette valeur,vous indiquez au navigateur que lorsqu'il doit charger la même URL au cours de l'année suivante (31 536 000 secondes,soit la valeur maximale acceptée), il peut utiliser immédiatement la valeur du cache HTTP, sans avoir à envoyer de requête réseau à votre serveur Web. C'est formidable : vous avez immédiatement gagné en fiabilité et en rapidité en évitant le réseau !
Les outils de compilation comme webpack peuvent automatiser le processus d'attribution d'empreintes de hachage aux URL de vos éléments.
Revalidation du serveur pour les URL sans version
Malheureusement, les URL que vous chargez ne sont pas toutes versionnées. 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 aux URL de vos éléments. De plus, chaque application Web a besoin de fichiers HTML. Ces fichiers n'incluront (presque !) jamais d'informations de gestion des versions, car personne ne prendra la peine d'utiliser votre application Web s'il doit se souvenir que l'URL à visiter est https://example.com/index.34def12.html. Que pouvez-vous faire pour ces URL ?
C'est un scénario dans lequel vous devez admettre votre défaite. 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 vous fourniront l'aide dont vous avez besoin pour faire pencher la balance en votre faveur.) Toutefois, vous pouvez prendre quelques mesures pour vous assurer que les requêtes réseau sont aussi rapides et efficaces que possible.
Les valeurs Cache-Control suivantes peuvent vous aider à affiner l'emplacement et la méthode de mise en cache des URL sans version :
no-cache. Cela indique au navigateur qu'il doit revalider auprès du serveur chaque fois qu'il utilise une version mise en cache de l'URL.no-store: indique au navigateur et aux autres caches intermédiaires (comme les CDN) de ne jamais stocker de version du fichier.private: les navigateurs peuvent mettre en cache le fichier, mais pas les caches intermédiaires.public: la réponse peut être stockée par n'importe quel cache.
Consultez l'Annexe : Organigramme Cache-Control pour visualiser le processus de décision concernant la ou les valeurs Cache-Control à utiliser. Cache-Control peut également accepter une liste de directives séparées par une virgule. Consultez Annexe : Exemples de Cache-Control.
Définir ETag ou Last-Modified peut également vous aider. Comme indiqué dans En-têtes de réponse, ETag et Last-Modified ont le même objectif : déterminer si le navigateur doit télécharger à nouveau un fichier mis en cache qui a expiré. Nous vous recommandons d'utiliser ETag, car il est plus précis.
Supposons que 120 secondes se soient écoulées depuis la récupération initiale et que le navigateur ait lancé une nouvelle requête pour la même ressource. Tout d'abord, le navigateur vérifie 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 elle a expiré. À ce stade, le navigateur peut envoyer une nouvelle requête et récupérer 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 mêmes informations que celles qui se trouvent déjà dans le cache.
C'est le problème que les jetons de validation, tels que spécifiés 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 doit simplement l'envoyer au serveur lors de la requête suivante. 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.
La définition de ETag ou Last-Modified rend la requête de revalidation 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ête entrants, il peut confirmer si la version de la ressource que le navigateur possède déjà dans son cache HTTP correspond à la dernière version sur le serveur Web. S'il y a une correspondance, le serveur peut répondre avec une réponse HTTP 304 Not Modified, ce qui équivaut à dire "Continuez à 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. C'est donc généralement beaucoup plus rapide que de devoir renvoyer une copie de la ressource demandée.
/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 ce cas, les deux valeurs correspondent. Le serveur renvoie donc une réponse 304 Not Modified avec des instructions sur la durée de mise en cache du fichier (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 ne nécessite pas beaucoup de travail de configuration.
Les configurations Cache-Control suivantes constituent un bon point de départ :
Cache-Control: no-cachepour les ressources qui doivent être revalidées avec le serveur avant chaque utilisation.Cache-Control: no-storepour les ressources qui ne doivent jamais être mises en cache.Cache-Control: max-age=31536000pour les ressources avec gestion des versions.
De plus, l'en-tête ETag ou Last-Modified peut vous aider à revalider plus efficacement les ressources de cache arrivées à expiration.
En savoir plus
Si vous souhaitez aller au-delà des principes de base de l'en-tête Cache-Control, consultez le guide de Jake Archibald sur les bonnes pratiques de mise en cache et les pièges de max-age.
Consultez Love your cache (en anglais) pour savoir comment optimiser l'utilisation du cache pour les visiteurs connus.
Annexe : Autres conseils
Si vous avez plus de temps, voici d'autres façons d'optimiser votre utilisation du cache HTTP :
- Utilisez des URL cohérentes. Si vous diffusez le même contenu sur différentes URL, ce contenu sera récupéré et stocké plusieurs fois.
- Réduire la perte d'utilisateurs Si une partie d'une ressource (comme un fichier CSS) est mise à jour fréquemment, alors que le reste du fichier ne l'est pas (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 de longue durée pour le code qui ne change pas souvent.
- Découvrez la nouvelle directive
stale-while-revalidatesi un certain degré d'obsolescence est acceptable dans votre règleCache-Control.
Annexe : Organigramme Cache-Control
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 un jour maximum (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. |