08 - Le cache HTTP : éviter les requêtes inutiles
Ce que tu vas apprendre
- Les directives Cache-Control et leur effet réel
- La validation conditionnelle avec ETag et Last-Modified
- Le rôle du header Vary pour les caches partages
- Comment un CDN utilise ces mecanismes
Prerequisites
Le cache HTTP est probablement le mecanisme le plus mal compris du protocole. Tout le monde sait que "ca met en cache", mais quand tu demandes la différence entre no-cache et no-store, le silence est assourdissant.
Je me souviens d'un bug en production ou une page affichait des donnees d'un autre utilisateur. Le coupable : un Cache-Control: public sur une réponse personnalisee. Le CDN avait mis en cache la page du premier visiteur et la servait a tout le monde. Deux caractères de trop, trois heures de debug.
Cache-Control : le chef d'orchestre
Le header Cache-Control dans la réponse dicte le comportement du cache. Voici les directives une par une.
max-age
Cache-Control: max-age=3600
Le navigateur garde la réponse pendant 3600 secondes. Pendant cette duree, il ne contacte meme pas le serveur. Zero requête réseau. C'est le cache dit "frais".
no-cache
Le nom est trompeur. no-cache ne signifie pas "ne mets pas en cache". Ca signifie "mets en cache, mais revalide a chaque fois auprès du serveur avant d'utiliser la copie". Le navigateur stocke la réponse, mais il demande au serveur si elle est encore bonne avant de la servir.
no-store
Ca, c'est le vrai "ne mets rien en cache". Ni mémoire, ni disque, rien. Pour les donnees sensibles (comptes bancaires, tokens), c'est no-store qu'il te faut.
public vs private
public autorise les caches partages (CDN, proxy d'entreprise) a stocker la réponse. private restreint au cache du navigateur uniquement. Une page avec le nom de l'utilisateur doit etre private. Un fichier CSS peut etre public.
s-maxage
Comme max-age, mais uniquement pour les caches partages. Tu peux avoir max-age=60, s-maxage=3600 : le navigateur garde 1 minute, le CDN garde 1 heure.
must-revalidate
Une fois la réponse perimee, le cache doit revalider auprès du serveur. Sans cette directive, certains caches servent du contenu perime en cas de problème réseau. Avec must-revalidate, c'est interdit : soit tu revalides, soit tu renvoies une erreur.
stale-while-revalidate
Cache-Control: max-age=3600, stale-while-revalidate=60
Pendant les 60 secondes apres expiration, le cache sert la version perimee tout en demandant la nouvelle en arriere-plan. L'utilisateur voit la page instantanement, et la prochaine visite aura la version à jour. C'est un compromis elegant entre fraicheur et performance.
Validation conditionnelle : le 304 Not Modified
Le cache expire. Mais ca ne veut pas dire que le contenu a change. La validation conditionnelle évité de retelecharger un fichier identique.
ETag + If-None-Match
Le serveur envoie un identifiant unique avec la réponse :
HTTP/1.1 200 OK
ETag: "abc123def456"
Content-Length: 45000
Au prochain acces, le navigateur demande :
GET /style.css HTTP/1.1
If-None-Match: "abc123def456"
Si le contenu n'a pas change, le serveur répond :
HTTP/1.1 304 Not Modified
Pas de body. Juste les headers. Le navigateur utilise sa copie locale. Tu economises la bande passante du transfert complet.
Last-Modified + If-Modified-Since
Meme principe, mais base sur la date :
HTTP/1.1 200 OK
Last-Modified: Mon, 15 Mar 2026 10:30:00 GMT
Le navigateur envoie ensuite :
GET /style.css HTTP/1.1
If-Modified-Since: Mon, 15 Mar 2026 10:30:00 GMT
ETag est plus precis (un fichier peut etre modifie puis revenir a l'identique), mais Last-Modified est plus simple a implementer. La plupart des serveurs web le font automatiquement pour les fichiers statiques.
Le header Vary : quand la meme URL donne des réponses différentes
Imagine une API qui renvoie du JSON ou du XML selon le header Accept. Le CDN cache la première réponse. Le deuxieme client demande un format différent et recoit la version cachee dans le mauvais format.
Le header Vary resout ca :
Vary: Accept, Accept-Encoding
Le cache créé une entree séparée pour chaque combinaison de valeurs des headers listes dans Vary. Meme URL, mais des caches différents selon Accept et Accept-Encoding.
Attention : Vary: * désactivé complètement le cache. C'est rarement ce que tu veux.
CDN et cache : la couche supplementaire
Un CDN (Cloudflare, Fastly, CloudFront) est un cache partage distribue geographiquement. Il respecte les memes headers Cache-Control, mais avec des subtilites.
Le pattern classique pour les assets statiques :
Cache-Control: public, max-age=31536000, immutable
Un an de cache. Le immutable dit au navigateur de ne meme pas revalider quand l'utilisateur recharge la page. Ca fonctionne parce que les fichiers ont un hash dans leur nom (style.a3f2b1.css). Si le contenu change, l'URL change.
Pour les pages HTML dynamiques, c'est différent :
Cache-Control: no-cache
Le CDN et le navigateur gardent la page, mais revalident systématiquement. Le serveur renvoie un 304 si rien n'a change, ou un 200 avec le nouveau contenu.
Sur paltemps.fr, on utilise ce pattern exact : assets immutables avec hash, HTML en no-cache. Le Time to First Byte tombe a quelques millisecondes pour les visiteurs réguliers.
Les erreurs classiques
Oublier private sur du contenu personnalise. Le CDN cache la réponse et la sert a tout le monde. Bug critique.
Mettre no-cache en pensant "pas de cache". Les développeurs confondent no-cache et no-store en permanence. Si tu veux zero cache, c'est no-store.
Ignorer Vary. Ton API sert du gzip et du brotli selon Accept-Encoding. Sans Vary: Accept-Encoding, le CDN peut servir du brotli a un vieux navigateur qui ne le supporte pas.
Des max-age trop longs sur du HTML. Changer une page HTML cachee un an chez le client, c'est impossible. Tu ne peux pas invalider le cache du navigateur. Les assets ont des hashes, pas le HTML.
Résumé
max-agecontrôle la duree de cache,no-cacheforce la revalidation,no-storeinterdit tout stockagepublicautorise les caches partages,privaterestreint au navigateur- ETag et Last-Modified permettent la validation conditionnelle avec des réponses 304
Varyséparé les entrees de cache selon les headers de la requête- Les CDN respectent ces memes mecanismes avec
s-maxagepour un contrôle spécifique - Le pattern hash + immutable pour les assets, no-cache pour le HTML
Article précédent : 07 - Cookies
Article suivant : 09 - TLS et HTTPS