Sauter la navigation
Partie IV Chapitre 16

Mise en cache

Introduction

La mise en cache est une technique permettant de réutiliser un contenu précédemment téléchargé. Elle offre un avantage significatif en termes de performance en évitant de rejouer de coûteuses requêtes. La mise en cache facilite la montée en charge d'une application, en réduisant le trafic sur le réseau à destination du serveur d'origine. Un vieux dicton dit que "la requête la plus rapide est celle que vous n'avez pas à faire " et la mise en cache est l'un des principaux moyens d'éviter d'avoir à refaire des requêtes.

La mise en cache sur le web s'appuie sur trois principes fondamentaux : mettre en cache autant que possible, aussi longtemps que possible et aussi près que possible des utilisateurs finaux.

Mettre en cache autant que vous le pouvez. Lorsque l'on s'intéresse aux données pouvant être mises en cache, il est important de débuter en identifiant les réponses statiques et dynamiques, qui évoluent ou non en fonction du contexte d'appel. Généralement, les réponses statiques, ne changeant pas, peuvent être mises en cache. Mettre en cache les réponses statiques permettra de les partager entre les utilisateurs. Les contenus dynamiques nécessitent, quant à eux, une analyse plus poussée.

Mettre en cache aussi longtemps que possible. La durée de mise en cache d'une ressource dépend fortement de sa sensibilité et de son contenu. Une ressource JavaScript versionnée peut être mise en cache pendant très longtemps, alors qu'une ressource non versionnée peut nécessiter une durée de cache plus courte afin de garantir aux utilisateurs de disposer des données a jour.

Cachez le plus près possible des utilisateurs finaux. Une mise en cache proche des utilisateurs réduit les temps de téléchargement en réduisant les latences réseau. Par exemple, pour une ressource mise en cache sur le navigateur de l'utilisateur, la requête ne sera jamais envoyée sur le réseau et le temps de téléchargement sera aussi rapide que les I/O de la machine. Pour les premiers visiteurs, ou les visiteurs qui n'ont pas encore leurs données cachées, un CDN est généralement la prochaine localisation d'une ressource cachée. Dans la plupart des cas, il sera plus rapide de récupérer une ressource à partir d'un cache local ou d'un CDN que sur le serveur d'origine.

Les architectures Web impliquent généralement une mise en cache en plusieurs niveaux. Par exemple une requête HTTP peut être mise en cache de différentes manière :

  • dans le cache du navigateur ;
  • dans le cache d'un service worker dans le navigateur ;
  • dans une passerelle partagée ;
  • au niveau des CDN, qui offrent la possibilité de mettre en cache à proximité des utilisateurs ;
  • dans un proxy de cache en amont des applications pour réduire la charge sur les serveurs back-end ;
  • au niveau de l'application et de la base de données.

Ce chapitre explique comment les ressources sont mises en cache dans les navigateurs Web.

Présentation de la mise en cache HTTP

Pour qu'un client HTTP mette en cache une ressource, il doit répondre a deux questions :

  • "Combien de temps dois-je mettre en cache ?"
  • "Comment puis-je valider que le contenu est encore frais ?"

Lorsqu'un navigateur Web envoie une réponse à un client, il inclut généralement dans sa réponse des en-têtes qui indiquent si la ressource peut être mise en cache, pour combien de temps et quel est son âge. La RFC 7234 traite plus en détail de ce point dans la section 4.2 (Freshness) et 4.3 (Validation).

Les en-têtes de réponse HTTP généralement utilisées pour transmettre la durée de vie sont :

  • Cache-Control vous permet de configurer la durée de vie du cache (c'est-à-dire sa durée de validité).
  • Expires fournit une date ou une heure d'expiration (c.-à-d. quand exactement celle-ci expire).

Cache-Control est prioritaire si les deux champs sont renseignés. Ces en-têtes sont abordés plus en détail ci-dessous.

Les en-têtes de réponse HTTP permettant de valider les données stockées en cache, c'est à dire donner les informations nécessaires pour comparer une ressource à sa contrepartie côté serveur :

  • Last-Modified indique quand la ressource a été modifiée pour la dernière fois.
  • ETag fournit l'identifiant unique d'une ressource.

ETag est prioritaire si les deux en-têtes sont renseignés. Ces en-têtes sont abordés plus en détail ci-dessous.

L'exemple ci-dessous contient un extrait d'un en-tête requête/réponse du fichier main.js de HTTP Archive. Ces en-têtes indiquent que la ressource peut être mise en cache pendant 43 200 secondes (12 heures), et qu'elle a été modifiée pour la dernière fois il y a plus de deux mois (différence entre les en-têtes Last-Modified et Date).

> GET /static/js/main.js HTTP/1.1
> Host: httparchive.org
> User-agent: curl/7.54.0
> Accept: */*

< HTTP/1.1 200
< Date: Sun, 13 Oct 2019 19:36:57 GMT
< Content-Type: application/javascript; charset=utf-8
< Content-Length: 3052
< Vary: Accept-Encoding
< Server: gunicorn/19.7.1
< Last-Modified: Sun, 25 Aug 2019 16:00:30 GMT
< Cache-Control: public, max-age=43200
< Expires: Mon, 14 Oct 2019 07:36:57 GMT
< ETag: "1566748830.0-3052-3932359948"

L'outil RedBot.org vous permet d'entrer une URL et de voir un rapport détaillé de la façon dont la réponse sera mise en cache en fonction de ses en-têtes. Par exemple,un test pour l'URL ci-dessus produirait ce qui suit :

Figure 1. Informations de RedBot relatives au Cache-Control.
Exemple de réponse Redbot montrant des informations détaillées sur le moment où la ressource a été modifiée ; si les caches peuvent la stocker ; pour combien de temps elle peut être considérée valide ; si nécessaire les avertissements.
Figure 1. Informations de RedBot relatives au Cache-Control.

Si aucun en-tête de mise en cache n'est renseigné dans la réponse, alors l'application peut mettre en cache en suivant une heuristique générique. La plupart des clients implémentent une variation de l'heuristique suggérée par le RFC, qui est 10 % du temps depuis le Last-Modified. Toutefois, certains peuvent mettre la réponse en cache indéfiniment. Il est donc important de définir des règles de mise en cache spécifiques pour s'assurer que vous maîtrisez la cachabilité.

72 % des réponses HTTP sont servies avec un en-tête Cache-Control, et 56 % des réponses sont servies avec un en-tête Expires. Cependant, 27 % des réponses n'utilisaient ni l'un ni l'autre, et peuvent alors être mises en cache en suivant cette heuristique. C'est un constat partagé par les sites pour ordinateurs de bureau et les sites mobiles.

Figure 2. Présence des en-têtes HTTP Cache-Control et Expires.
Ces deux diagrammes à barres identiques pour le mobile et les ordinateurs de bureau montrent que 72 % des requêtes utilisent des en-têtes Cache-Control et que 56 % utilisent Expires et les 27 % n'utilisent aucun des deux.
Figure 2. Présence des en-tête HTTP Cache-Control et Expires.

Quel type de contenu met-on en cache ?

Une ressource mise en cache est stockée par le client pendant un certain temps et peut être réutilisée ultérieurement. Pour les requêtes HTTP, 80 % des réponses peuvent certainement être mises en cache, ce qui signifie qu'un système de cache peut les stocker. En dehors de ça,

  • 6 % des requêtes ont un Time To Live (TTL) de 0 seconde, qui invalide immédiatement une entrée en cache.
  • 27 % sont mis en cache par heuristique, à cause d'un Cache-Control manquant en en-tête.
  • 47 % sont mis en cache pendant plus de 0 seconde.

Les autres réponses ne peuvent pas être stockées dans le cache du navigateur.

Figure 3. Distribution des réponses pouvant être mises en cache.
Un graphique à barres superposées montrant que 20 % des réponses pour ordinateurs de bureau ne peuvent être mises en cache, 47 % ont un cache supérieur à zéro, 27 % sont mises en cache de manière heuristique et 6 % ont un TTL de 0. Les statistiques pour les mobiles sont très similaires (19 %, 47 %, 27 % et 7 %)
Figure 3. Distribution des réponses pouvant être mises en cache.

Le tableau ci-dessous détaille les TTL du cache pour les requêtes en provenance d'ordinateurs de bureau. La plupart des types de contenu sont mis en cache, mais les ressources CSS semblent toujours être mises en cache à des valeurs TTL élevées.

Percentiles TTL du cache des ordinateurs de bureau (Heures)
10 25 50 75 90
Audio

12

24

720

8,760

8,760

CSS

720

8,760

8,760

8,760

8,760

Police d'écriture

< 1

3

336

8,760

87,600

HTML

< 1

168

720

8,760

8,766

Image

< 1

1

28

48

8,760

Autre

< 1

2

336

8,760

8,760

Script

< 1

< 1

1

6

720

Texte

21

336

7,902

8,357

8,740

Vidéo

< 1

4

24

24

336

XML

< 1

< 1

< 1

< 1

< 1

Figure 4. Percentiles du TTL par type de ressources, pour ordinateurs de bureau.

Bien que la plupart des TTL médians sont élevées, les percentiles inférieurs mettent en évidence certaines occasions manquées de mise en cache. Par exemple, le TTL médian pour les images est de 28 heures, mais le 25e percentile n'est que d'une à deux heures et le 10e percentile indique que 10 % du volume d'images en cache l'est pendant moins d'une heure.

En explorant plus en détail les possibilités de mise en cache par type de contenu dans la figure 5 ci-dessous, nous pouvons voir qu'environ la moitié de toutes les réponses HTML sont considérées comme non cachables. De plus, 16 % des images et des scripts ne peuvent pas être mis en cache.

Figure 5. Distribution de la cachabilité pour les types de contenu destinés aux ordinateurs de bureau.
Un diagramme à barres montrant la répartition des éléments non cachables, mis en cache pendant plus de 0 seconde et mis en cache pendant seulement 0 seconde par type pour les ordinateurs de bureau. Une petite, mais significative proportion n'est pas cachable et cela va jusqu'à 50 % pour le HTML, la plupart ont une mise en cache supérieure à 0 et une plus petite quantité a un TTL de 0
Figure 5. Distribution de la cachabilité pour les types de contenu destinés aux ordinateurs de bureau.

Les mêmes données pour le mobile sont présentées ci-dessous. Comme on peut le voir, la mise en cache des types de contenu est similaire entre les ordinateurs de bureau et les mobiles.

Figure 6. Distribution de la cachabilité pour les types de contenu mobile.
Un diagramme à barres montrant la répartition des éléments non cachables, mis en cache pendant plus de 0 seconde et mis en cache pendant seulement 0 seconde par type pour les ordinateurs de bureau. Une petite, mais significative proportion n'est pas cachable et cela va jusqu'à 50 % pour le HTML, la plupart ont une mise en cache supérieure à 0 et une plus petite quantité a un TTL de 0
Figure 6. Distribution de la cachabilité pour les types de contenu mobile.

Cache-Control vs Expires

Dans HTTP/1.0, l'en-tête Expires était utilisé pour indiquer la date/heure après laquelle la réponse était considérée comme périmée. Sa valeur est un horodatage, par exemple :

Expires: Thu, 01 Dec 1994 16:00:00 GMT

HTTP/1.1 a introduit l'en-tête Cache-Control, et la plupart des clients modernes supportent les deux en-têtes. Cet en-tête est beaucoup plus extensible, via des directives de mise en cache. Par exemple :

  • no-store peut être utilisé pour indiquer qu'une ressource ne doit pas être mise en cache.
  • max-age peut être utilisé pour indiquer une durée de vie.
  • must-revalidate indique au client que la ressource mise en cache doit être revalidée avec une requête conditionnelle avant son utilisation.
  • private indique qu'une réponse ne doit être mise en cache que par un navigateur, et non par un intermédiaire qui servirait plusieurs clients.

53 % des réponses HTTP incluent un en-tête Cache-Control avec la directive max-age, et 54 % incluent l'en-tête Expires. Cependant, seulement 41 % de ces réponses utilisent les deux en-têtes, ce qui signifie que 13 % des réponses sont basées uniquement sur l'ancien en-tête Expires.

Figure 7. Utilisation comparée des en-têtes Cache-Control et Expires.
Un diagramme à barres montrant que 53 % des réponses ont un `Cache-Control: max-age`, 54 %-55 % utilisent `Expire`, 41 %-42 % utilisent les deux, et 34 % n'utilisent aucun des deux. Les chiffres sont donnés à la fois pour les ordinateurs de bureau et les mobiles, mais les chiffres sont presque identiques, les mobiles ayant un point de pourcentage d'utilisation des expirations plus élevé.
Figure 7. Utilisation comparée des en-têtes Cache-Control et Expires.

Directives Cache-Control

La specification HTTP/1.1 inclut de multiples directives qui peuvent être utilisées dans l'en-tête de réponse Cache-Control et sont détaillées ci-dessous. Notez que plusieurs directives peuvent être utilisées dans une seule réponse.

Directive Description
max-age Indique le nombre de secondes pendant lesquelles une ressource peut être mise en cache.
public N'importe quel cache peut stocker la réponse.
no-cache Une entrée en cache doit être revalidée avant son utilisation.
must-revalidate Une entrée en cache périmée doit être revalidée avant son utilisation.
no-store Indique qu'une réponse ne doit pas être mise en cache.
private La réponse est destinée à un utilisateur spécifique et ne doit pas être stockée par des caches partagés.
no-transform Aucune transformation ou conversion ne doit être effectuée sur cette ressource.
proxy-revalidate Identique à must-revalidate mais pour les caches partagés.
s-maxage Identique à l'âge maximum mais pour les caches partagés.
immutable Indique que l'entrée en cache ne changera jamais, et qu'une revalidation n'est pas nécessaire.
stale-while-revalidate Indique que le client est prêt à accepter une réponse périmée tout en vérifiant de manière asynchrone en arrière-plan l'existence d'une ressource plus fraiche.
stale-if-error Indique que le client est prêt à accepter une réponse périmée même si la vérification qu'une ressource plus fraiche échoue.
Figure 8. Cache-Control directives.

Par exemple, cache-control:public, max-age=43200 indique qu'une entrée mise en cache doit être stockée pendant 43.200 secondes et qu'elle peut être stockée par tous les caches.

Figure 9. Utilisation de la directive Cache-Control sur mobile.
Un diagramme à barres de 15 directives `Cache-Control` et leur utilisation allant de 74,8 % pour max-age, 37,8 % pour public, 27,8 % pour no-cache, 18 % pour no-store, 14,3 % pour private, 3,4 % pour l'immutable, 3.3. 3 % pour no-transform, 2,4 % pour le stale-while-revalidate, 2,2 % pour pre-check, 2,2 % pour post-check, 1,9 % pour s-maxage, 1,6 % pour proxy-revalidate, 0,3 % pour le set-cookie et 0,2 % pour le stale-if-error. Les statistiques sont presque identiques pour les ordinateurs de bureaux et les téléphones portables.
Figure 9. Utilisation de la directive Cache-Control sur mobile.

La figure 9 ci-dessus illustre les 15 directives Cache-Control les plus utilisées sur les sites Web mobiles. Les résultats pour les sites destinés aux ordinateurs de bureau et les sites mobiles sont très similaires. Il y a quelques observations intéressantes sur la popularité de ces directives de cache :

  • max-age est utilisé par presque 75 % des en-têtes Cache-Control, et no-store est utilisé par 18 %.
  • public (publique) est rarement nécessaire car les entrées en cache sont supposées public à moins que private (privé) ne soit spécifié. Environ 38 % des réponses incluent public.
  • La directive immutable est relativement nouvelle, introduite en 2017 et est supportée par Firefox et Safari. Son utilisation a augmenté à 3,4 % et elle est largement utilisée dans les réponses des tierces parties de Facebook et Google.

Un autre ensemble intéressant de directives à faire apparaître dans cette liste sont pre-check et post-check, qui sont utilisées dans 2,2 % des en-têtes Cache-Control (environ 7,8 millions de réponses). Cette paire d'en-têtes a été introduite dans Internet Explorer 5 pour fournir une validation en arrière-plan et a rarement été implémentée correctement par les sites web. 99,2 % des réponses utilisant ces en-têtes avaient utilisé la combinaison pre-check=0 et post-check=0. Quand ces deux directives sont mises à 0, alors les deux directives sont ignorées. Il semble donc que ces directives n'aient jamais été utilisées correctement !

Il y a plus de 1 500 directives erronées utilisées dans 0,28 % des réponses. Ces directives sont ignorées par les clients, comprennent des erreurs d'orthographe telles que nocache, s-max-age, smax-age et maxage. Il y a aussi de nombreuses directives inexistantes comme max-stale, proxy-public, subsrogate-control, etc.

Cache-Control : no-store, no-cache et max-age=0

Lorsqu'une réponse ne doit pas être mise en cache, la directive Cache-Control no-store doit être utilisée. Si cette directive n'est pas utilisée, alors la réponse peut être mise en cache.

Il y a quelques erreurs courantes, commises lorsqu'on essaie de configurer une réponse pour qu'elle ne puisse pas être mise en cache :

  • configurer Cache-Control: no-cache peut donner l'impression que la ressource ne doit pas être mise en cache. En réalité, no-cache précise que l'entrée mise en cache doit être revalidée avant d'être utilisée et n'indique pas que la ressource ne peut pas être mise en cache.
  • Cache-Control: max-age=0 fixe le TTL à 0 seconde, mais ce n'est pas la même chose que de ne pas pouvoir mettre en cache. Quand max-age est fixé à 0, la ressource est stockée dans le cache du navigateur et immédiatement invalidée. Le navigateur doit donc effectuer une requête conditionnelle pour valider la fraîcheur de la ressource.

Fonctionnellement, no-cache et max-age=0 sont similaires, puisqu'ils nécessitent tous deux la revalidation d'une ressource mise en cache. La directive no-cache peut aussi être utilisée avec une directive max-age supérieure à 0.

Plus de 3 millions de réponses comprennent la combinaison de no-store, no-cache, et max-age=0. Parmi ces directives, no-store est prioritaire et les autres directives sont simplement redondantes.

18 % des réponses comprennent no-store et 16,6 % des réponses comprennent à la fois no-store et no-cache. Puisque no-store a la priorité, la ressource n'est finalement pas cachable.

La directive max-age=0 est présente sur 1,1 % des réponses (plus de quatre millions de réponses) où no-store n'est pas présent. Ces ressources seront mises en cache dans le navigateur mais devront être revalidées car elles sont immédiatement expirées.

Comment les TTL de cache se comparent-ils à l'âge des ressources ?

Jusqu'à présent, nous avons parlé de la façon dont les serveurs Web indiquent à un client ce qui peut être mis en cache, et pendant combien de temps. Lors de la conception des règles de mise en cache, il est également important de comprendre l'âge du contenu que vous servez.

Lorsque vous choisissez un cache TTL, demandez-vous : "à quelle fréquence allez-vous mettre à jour ces ressources ?" et "quelle est la sensibilité de leur contenu ?". Par exemple, si une Hero Image va être modifiée peu fréquemment, alors cachez-la avec un TTL très long. Si vous vous attendez à ce qu'une ressource JavaScript soit modifiée fréquemment, alors versionnez-la puis mettez-la en cache avec un long TTL ou cachez-la avec un TTL plus court.

Le graphique ci-dessous illustre l'âge relatif des ressources par type de contenu, et vous pouvez lire une analyse plus détaillée ici. Le HTML tend à être le type de contenu ayant l'âge le plus court, et un très grand pourcentage des ressources traditionnellement mises en cache (scripts, CSS, et polices d'écriture) ont plus d'un an !

Figure 10. Répartition de l'âge des ressources par type de contenu.
Un diagramme à barres indiquant l'âge du contenu, divisé en semaines 0-52, > un an et > deux ans, avec des chiffres nuls et négatifs. Les statistiques sont divisées entre ressources principales et ressources de tierces parties. La valeur 0 est utilisée plus particulièrement pour le HTML, le texte et le XML issue du domaine principal. C'est également le cas pour plus de 50 % des requêtes de tiers dans tous les types de ressources. Il existe un mélange utilisant des portions d'années, puis une utilisation considérable pendant un an et deux ans.
Figure 10. Répartition de l'âge des ressources par type de contenu.

En comparant la capacité de mise en cache d'une ressource à son âge, nous pouvons déterminer si le TTL est approprié ou trop faible. Par exemple, la ressource servie par la réponse ci-dessous a été modifiée pour la dernière fois le 25 août 2019, ce qui signifie qu'elle avait 49 jours au moment où elle a été servie. L'en-tête Cache-Control indique que nous pouvons la mettre en cache pendant 43 200 secondes, soit 12 heures. La ressource est largement assez vieille pour mériter qu'on se demande si un TTL plus long serait approprié.

< HTTP/1.1 200
< Date: Sun, 13 Oct 2019 19:36:57 GMT
< Content-Type: application/javascript; charset=utf-8
< Content-Length: 3052
< Vary: Accept-Encoding
< Server: gunicorn/19.7.1
< Last-Modified: Sun, 25 Aug 2019 16:00:30 GMT
< Cache-Control: public, max-age=43200
< Expires: Mon, 14 Oct 2019 07:36:57 GMT
< ETag: "1566748830.0-3052-3932359948"

Dans l'ensemble, 59 % des ressources servies sur le Web ont un TTL de cache trop court par rapport à l'âge de leur contenu. De plus, le delta médian entre le TTL et l'âge est de 25 jours.

Si l'on compare les ressources du domaine principal et celles des tierces parties, on constate que 70 % des ressources du domaine principal peuvent bénéficier d'une durée de vie plus longue. Cela met clairement en évidence la nécessité d'accorder une attention particulière à ce qui peut être mis en cache, puis de s'assurer que la mise en cache est configurée correctement.

Client 1ere partie 3e partie Global
Bureau

70.7 %

47.9 %

59.2 %

Mobile

71.4 %

46.8 %

59.6 %

Figure 11. Pourcentage des requêtes avec des TTL courts.

Validation de la fraîcheur des informations

Les en-têtes HTTP utilisés pour valider les réponses stockées dans un cache sont Last-Modified et ETag. L'en-tête Last-Modified fait exactement ce que son nom implique et fournit l'heure à laquelle l'objet a été modifié pour la dernière fois. L'en-tête ETag fournit un identifiant unique pour le contenu.

Par exemple, la réponse ci-dessous a été modifiée pour la dernière fois le 25 août 2019 et elle a une valeur ETag de "1566748830.0-3052-3932359948".

< HTTP/1.1 200
< Date: Sun, 13 Oct 2019 19:36:57 GMT
< Content-Type: application/javascript; charset=utf-8
< Content-Length: 3052
< Vary: Accept-Encoding
< Server: gunicorn/19.7.1
< Last-Modified: Sun, 25 Aug 2019 16:00:30 GMT
< Cache-Control: public, max-age=43200
< Expires: Mon, 14 Oct 2019 07:36:57 GMT
< ETag: "1566748830.0-3052-3932359948"

Un client peut envoyer une requête conditionnelle pour valider une entrée en cache en utilisant la valeur Last-Modified dans un en-tête de requête nommé If-Modified-Since. De même, il pourrait aussi valider la ressource avec un en-tête de requête If-None-Match, qui valide par rapport à la valeur ETag que le client a pour la ressource dans son cache.

Dans l'exemple ci-dessous, le cache semble toujours valide, et un HTTP 304 a été renvoyé sans contenu. Cela permet d'économiser le téléchargement de la ressource elle-même. Si l'entrée de cache n'était plus fraîche, alors le serveur aurait répondu avec un 200 et la ressource mise à jour qui aurait dû être téléchargée à nouveau.

> GET /static/js/main.js HTTP/1.1
> Host: www.httparchive.org
> User-Agent: curl/7.54.0
> Accept: */*
> If-Modified-Since: Sun, 25 Aug 2019 16:00:30 GMT

< HTTP/1.1 304
< Date: Thu, 17 Oct 2019 02:31:08 GMT
< Server: gunicorn/19.7.1
< Cache-Control: public, max-age=43200
< Expires: Thu, 17 Oct 2019 14:31:08 GMT
< ETag: "1566748830.0-3052-3932359948"
< Accept-Ranges: bytes

Dans l'ensemble, 65 % des réponses sont servies avec un en-tête Last-Modified, 42 % sont servies avec un ETag, et 38 % utilisent les deux. Cependant, 30 % des réponses n'incluent ni un en-tête Last-Modified ni un en-tête ETag.

Figure 12. Adoption de la validation de la fraîcheur par en-têtes Last-Modified et ETag pour sites sur ordinateurs de bureau.
Le diagramme à barres montre que 64,4 % des requêtes sur ordinateurs de bureau ont un Last Modified, 42,8 % ont un ETag, 37,9 % ont les deux et 30,7 % n'ont ni l'un ni l'autre. Les statistiques pour les mobiles sont presque identiques : 65,3 % pour la dernière modification, 42,8 % pour l'ETag, 38,0 % pour les deux et 29,9 % pour aucune des deux.
Figure 12. Adoption de la validation de la fraîcheur via les en-têtes Last-Modified et ETag pour sites sur ordinateurs de bureau.

Validité des dates

Le format des en-têtes HTTP utilisés pour transmettre les horodatages, et le format de ceux-ci, sont importants. L'en-tête Date indique quand la ressource a été servie à un client. L'en-tête Last-Modified indique quand une ressource a été modifiée pour la dernière fois sur le serveur. Et l'en-tête Expires est utilisé pour indiquer combien de temps une ressource doit être mise en cache (à moins qu'un en-tête Cache-Control soit présent).

Tous ces en-têtes HTTP utiliser des dates sous forme de chaine de carractères pour représenter des horodatages.

Par exemple :

> GET /static/js/main.js HTTP/1.1
> Host: httparchive.org
> User-Agent: curl/7.54.0
> Accept: */*

< HTTP/1.1 200
< Date: Sun, 13 Oct 2019 19:36:57 GMT
< Content-Type: application/javascript; charset=utf-8
< Content-Length: 3052
< Vary: Accept-Encoding
< Server: gunicorn/19.7.1
< Last-modified: Sun, 25 Aug 2019 16:00:30 GMT
< Cache-Control: public, max-age=43200
< Expires: Mon, 14 Oct 2019 07:36:57 GMT
< ETag: "1566748830.0-3052-3932359948"

La plupart des clients ignorent les dates invalides, ce qui les rend incapables de comprendre la réponse qui leur est servie. Cela peut avoir des conséquences sur la possibilité de mise en cache, puisqu'un en-tête Last-Modified erroné sera mis en cache sans l'horodatage Last-Modified, ce qui rendra impossible l'exécution d'une requête conditionnelle.

L'en-tête de réponse HTTP Date est généralement généré par le serveur web ou le CDN qui sert la réponse à un client. Comme l'en-tête est généralement généré automatiquement par le serveur, il a tendance à être moins sujet aux erreurs, ce qui se reflète dans le très faible pourcentage d'en-têtes Date invalides. Les en-têtes Last-Modified sont très similaires, avec seulement 0,67 % d'en-têtes invalides. Ce qui est très surprenant, c'est que 3,64 % des en-têtes Expires utilisent un format de date invalide !

Figure 13. Formats de date non valides dans les en-têtes de réponse.
Le diagramme à barres montre que 0,10 % des réponses sur ordinateurs de bureau ont une date non valide, 0,67 % ont une date Last-Modified non valide et 3,64 % ont une date d'Expires non valide. Les statistiques pour les mobiles sont très similaires avec 0,06 % des réponses ayant une date non valide, 0,68 % ayant une date Last-Modified non valide et 3,50 % ayant une date d'Expires non valide.
Figure 13. Formats de date invalides dans les en-têtes de réponse.

Voici des exemples d'utilisations incorrectes de l'en-tête Expires :

  • Formats de date valides, mais utilisant un fuseau horaire autre que GMT
  • Valeurs numériques telles que 0 ou -1
  • Valeurs qui seraient valides dans un en-tête Cache-Control

La plus grande source d'en-têtes Expires invalides provient de ressources servies par une tierce partie , dans lesquels un horodatage utilise le fuseau horaire EST, par exemple Expires: Tue, 27 Apr 1971 19:44:06 EST.

En-tête Vary

L'une des étapes les plus importantes de la mise en cache est de déterminer si la ressource demandée est mise en cache ou non. Bien que cela puisse paraître simple, il arrive souvent que l'URL seule ne suffise pas à le déterminer. Par exemple, les requêtes ayant la même URL peuvent varier en fonction de la compression utilisée (gzip, brotli, etc.) ou être modifiées et adaptées aux visiteurs mobiles.

Pour résoudre ce problème, les clients donnent à chaque ressource mise en cache un identifiant unique (une clé de cache). Par défaut, cette clé de cache est simplement l'URL de la ressource, mais les développeurs et développeuses peuvent ajouter d'autres éléments (comme la méthode de compression) en utilisant l'en-tête Vary.

Un en-têteVary demande au client d'ajouter la valeur d'une ou plusieurs valeurs d'en-tête de requête à la clé de cache. L'exemple le plus courant est Vary&nbsp;: Accept-Encoding, qui se traduira par différentes entrées en cache pour les valeurs d'en-tête de requête Accept-Encoding (c'est-à-dire gzip, br, deflate).

Une autre valeur commune est Vary: Accept-Encoding, User-Agent, qui demande au client de varier l'entrée en cache à la fois par les valeurs de Accept-Encoding et par la chaîne User-Agent. Lorsqu'il s'agit de proxies et de CDN partagés, l'utilisation de valeurs autres que Accept-Encoding peut être problématique car elle dilue les clés de cache et peut réduire le volume de trafic servi à partir du cache.

En général, vous ne devez modifier le cache que si vous servez un contenu alternatif aux clients en fonction de cet en-tête.

L'en-tête Vary est utilisé sur 39 % des réponses HTTP, et 45 % des réponses qui incluent un en-tête Cache-Control.

Le graphique ci-dessous détaille la popularité des 10 premières valeurs d'en-tête Vary. L'Accept-Encoding représente 90 % de l'utilisation de Vary, avec User-Agent (11 %), Origin (9 %), et Accept (3 %) constituant la majeure partie du reste.

Figure 14. Utilisation de l'en-tête Vary.
Le diagramme à barres montre que 90 % des utilisations se basent sur accept-encoding, et pour le reste des valeurs beaucoup plus petites avec 10 à 11 % pour l'user-agent, environ 7 à 8 % pour origin et moins pour accept, presque pas d'utilisation pour les en-têtes cookie, x-forward-proto, accept-language, host, x-origin, access-control-request-method, et access-control-request-heads
Figure 14. Utilisation de l'en-tête Vary.

L'utilisation de cookies pour la mise en cache des réponses

Lorsqu'une réponse est mise en cache, tous ses en-têtes sont également stockés dans le cache. C'est pourquoi vous pouvez voir les en-têtes de réponse lorsque vous inspectez une réponse mise en cache via DevTools.

Figure 15. Outils de développement Chrome pour une ressource en cache.
Une capture d'écran de Chrome Developer Tools montrant les en-têtes de réponse HTTP pour une réponse en cache.
Figure 15. Outils de développement Chrome pour une ressource en cache.

Mais que se passe-t-il si vous avez un Set-Cookie dans une réponse ? Selon la RFC 7234 Section 8, la présence d'un en-tête de réponse Set-Cookie n'empêche pas la mise en cache. Cela signifie qu'une entrée mise en cache peut contenir un Set-Cookie si elle a été mise en cache avec. La RFC recommande ensuite que vous configuriez des en-têtes Cache-Control appropriés pour contrôler la mise en cache des réponses.

L'un des risques de la mise en cache avec Set-Cookie est que les valeurs des cookies puissent être stockées et servies à des requêtes ultérieures. Suivant l'objectif du cookie, cela pourrait avoir des résultats inquiétants. Par exemple, si un cookie de connexion ou un cookie de session est présent dans un cache partagé, alors ce cookie pourrait être réutilisé par un autre client. Une façon d'éviter cela est d'utiliser la directive Cache-Control private, qui permet uniquement la mise en cache de la réponse par le navigateur du client.

3 % des réponses pouvant être mises en cache contiennent un en-tête Set-Cookie. Parmi ces réponses, seulement 18 % utilisent la directive private. Les 82 % restants comprennent 5,3 millions de réponses HTTP qui incluent un Set-Cookie qui peut être mis en cache par des serveurs de cache publics et privés.

Figure 16. Réponses cachables avec Set-Cookie.
Le graphique à barres montre que 97 % des réponses n'utilisent pas Set-Cookie alors que 3 % le font. Ces 3 % sont zoomés pour obtenir un autre diagramme à barres montrant la répartition entre 15,3 % de réponses private, 84,7 % de réponses public pour les ordinateurs de bureau et réciproquement pour les téléphones portables, 18,4 % de réponses public et 81,6 % de réponses private.
Figure 16. Réponses pouvant être mises en cache avec Set-Cookie.

AppCache et service workers

L'Application Cache ou AppCache est une fonctionnalité de HTML5 qui permet aux développeurs et développeuses de spécifier les ressources que le navigateur doit mettre en cache et mettre à disposition des utilisateurs hors ligne. Cette fonctionnalité a été dépréciée et supprimée des standards du web, et sa prise en charge par les navigateurs a diminué. En fait, lorsque son utilisation est détectée, Firefox v44+ recommande aux développeurs et développeuses d'utiliser plutôt des service workers. Chrome 70 limite le cache d'application au seul contexte sécurisé. Le secteur s'est davantage orienté vers la mise en œuvre de ce type de fonctionnalité avec des service workers - et la prise en charge des navigateurs a connu une croissance rapide dans ce domaine.

En fait, l'un des rapports de tendance des archives HTTP montre l'adoption des travailleurs des services présenté ci-dessous :

Figure 17. Série chronologique de pages contrôlées par des service worker.
Un graphique de séries chronologiques montre l'utilisation des sites contrôlés par les service worker d'octobre 2016 à juillet 2019. L'utilisation a augmenté régulièrement au fil des ans, tant pour les téléphones portables que pour les ordinateurs de bureau, mais reste inférieure à 0,6 % pour les deux.
Figure 17. Série chronologique de pages contrôlées par des service workers. (Source : HTTP Archive)

L'adoption est toujours inférieure à 1 % des sites web, mais elle est en constante augmentation depuis janvier 2017. Le chapitre Progressive Web App en parle davantage, notamment du fait qu'ils sont beaucoup plus utilisés que ne le suggère ce graphique en raison de leur utilisation sur des sites populaires, qui ne sont comptés qu'une fois dans le graphique ci-dessus.

Dans le tableau ci-dessous, vous pouvez voir un résumé de l'utilisation d'AppCache par rapport aux service workers. 32 292 sites web ont mis en place un service worker, tandis que 1 867 sites utilisent toujours la fonctionnalité AppCache, qui est obsolète.

N'utilisent pas de Server Worker Utilisent un Service Worker Total
N'utilise pas AppCache

5,045,337

32,241

5,077,578

Utilise AppCache

1,816

51

1,867

Total

5,047,153

32,292

5,079,445

Figure 18. Nombre de sites web utilisant AppCache par rapport aux Service Workers.

Si on fait une comparaison entre HTTP et HTTPS, cela devient encore plus intéressant. 581 des sites compatibles avec l'AppCache sont servis en HTTP, ce qui signifie que Chrome a probablement désactivé cette fonctionnalité. Le HTTPS est obligatoire pour l'utilisation des services workers, mais 907 des sites qui les utilisent sont servis en HTTP.

N'utilise pas Service Worker Utilise Service Worker
HTTP N'utilise pas AppCache

1,968,736

907

Utilise AppCache

580

1

HTTPS N'utilise pas AppCache

3,076,601

31,334

Utilise AppCache

1,236

50

Figure 19. Nombre de sites web utilisant AppCache par rapport à l'utilisation des service worker par HTTP/HTTPS.

Identifier les possibilités de mise en cache

L'outil Lighthouse de Google permet aux utilisateurs d'effectuer une série d'audits sur les pages web, et l'audit de la politique de cache évalue si un site peut bénéficier d'une mise en cache supplémentaire. Pour ce faire, il compare l'âge du contenu (via l'en-tête Last-Modified) au TTL de la ressource en cache et estime la probabilité que la ressource soit servie à partir du cache. En fonction du score, vous pouvez voir dans les résultats une recommandation de mise en cache, avec une liste de ressources spécifiques qui pourraient être mises en cache.

Figure 20. Rapport Lighthouse soulignant les améliorations possibles de la politique des caches.
Une capture d'écran d'une partie d'un rapport de l'outil Google Lighthouse, avec la section "Servir des ressources statiques avec une politique de cache efficace" ouverte où il énumère un certain nombre de ressources, dont les noms ont été masqués, et le TTL du cache par rapport à la taille.
Figure 20. Rapport Lighthouse soulignant les améliorations possibles de la politique des caches.

Lighthouse calcule un score pour chaque audit, allant de 0 à 100 %, et ces scores sont ensuite pris en compte dans les scores globaux. Le score de mise en cache est basé sur les économies potentielles d'octets. En examinant les résultats de Lighthouse, on peut se faire une idée du nombre de sites qui réussissent bien avec leur politique de cache.

Figure 21. Distribution des scores Lighthouse pour l'audit "Définit un long cache TTL" pour les pages web mobiles.
Un diagramme à barres superposées : 38,2 % des sites web obtiennent un score de < 10 %, 29,0 % des sites web obtiennent un score entre 10 et 39 %, 18,7 % des sites web obtiennent un score de 40 à 79 %, 10,7 % des sites web obtiennent un score de 80 à 99 %, et 3,4 % des sites web obtiennent un score de 100 %.
Figure 21. Distribution des scores Lighthouse pour l'audit "Définit un long cache TTL" pour les pages web mobiles.

Seuls 3,4 % des sites ont obtenu un score de 100 %, ce qui signifie que la plupart des sites peuvent bénéficier de certaines optimisations du cache. La grande majorité des sites ont un score inférieur à 40 %, 38 % ayant un score inférieur à 10 %. En partant de là, on peut affirmer qu'il existe un nombre important d'opportunités de mise en cache sur le web.

Lighthouse indique également combien d'octets pourraient être économisés sur les vues répétées en permettant une politique de cache plus longue. Parmi les sites qui pourraient bénéficier d'une mise en cache supplémentaire, 82 % d'entre eux peuvent réduire le poids de leurs pages jusqu'à un Mo entier !

Figure 22. Répartition des économies potentielles d'octets résultant de l'audit de la mise en cache de Lighthouse.
Un diagramme à barres superposées montrant que 56,8 % des sites web ont un potentiel d'économie d'octets de moins d'un Mo, 22,1 % pourraient avoir une économie d'un à deux Mo, 8,3 % pourraient économiser deux à trois Mo. 4,3 % pourraient permettre d'économiser trois à quatre Mo et 6,0 % pourraient permettre d'économiser plus de quatre Mo.
Figure 22. Répartition des économies potentielles d'octets résultant de l'audit de la mise en cache de Lighthouse.

Conclusion

La mise en cache est une fonction incroyablement puissante qui permet aux navigateurs, aux serveurs de proxy et autres intermédiaires (tels que les CDN) de stocker le contenu du web et de le servir aux utilisateurs finaux. Les avantages en termes de performances sont considérables, puisqu'elle réduit les temps de trajet (aller-retour) et minimise les requêtes coûteuses sur le réseau.

La mise en cache est également un sujet très complexe. Il existe de nombreux en-têtes de réponse HTTP qui peuvent transmettre la fraîcheur ainsi que valider les entrées mises en cache, et les directives Cache-Control offrent une très grande souplesse et un très grand contrôle. Cependant, les développeurs et développeuses doivent être prudent·e·s quant aux possibilités supplémentaires d'erreurs que ces directives offrent. Il est recommandé de vérifier régulièrement votre site pour s'assurer que les ressources pouvant être mises en cache le sont correctement, et des outils comme Lighthouse et REDbot font un excellent travail pour aider à simplifier l'analyse.

Auteur·ice