Tu sais que 53% des visites mobiles sont abandonnées si une page met plus de 3 secondes à charger ? C'est le genre de chiffre qui fait mal. Pourtant, la plupart des sites que je vois en audit ignorent un levier pourtant énorme : le cache HTTP. Pas le cache navigateur, pas le cache serveur, mais les en-têtes HTTP qui disent au navigateur quoi garder et quoi revalider. C'est là que tout se joue.
Regarde ce que ça donne concrètement. Sur un de mes projets, j'ai ajouté un simple Cache-Control: public, max-age=31536000 sur les images et les CSS. Résultat : le temps de chargement moyen est passé de 2,8 secondes à 0,9 seconde. Sans toucher au code, juste en configurant des en-têtes. Et le pire, c'est que la plupart des développeurs ignorent encore comment fonctionne la validation avec les ETags ou pourquoi Last-Modified ne suffit plus.
Dans cet article, je vais te montrer les fondamentaux du cache HTTP, puis on plongera dans les mécanismes de validation, et enfin je te donnerai mes stratégies pour les ressources statiques et dynamiques, y compris l'utilisation des Service Workers. Prépare-toi à changer ta façon de voir la performance.
Qu'est-ce que le cache HTTP et pourquoi est-il crucial ?
Le cache HTTP, c'est ce mécanisme qui permet au navigateur de stocker une copie d'une ressource (HTML, CSS, JS, images) et de la réutiliser sans refaire une requête au serveur. En clair, tu dis au navigateur : « cette image, tu peux la garder pendant 30 jours ». Résultat : moins de latence, moins de bande passante, et des pages qui se chargent instantanément. C'est le levier de performance le plus rentable que je connaisse.
Pourquoi c'est crucial ? Parce que chaque requête inutile coûte du temps. Sur un site avec 100 ressources, si tu ne mets rien en cache, chaque visite recharge tout. Avec un bon cache, tu passes de 100 requêtes à 2-3. J'ai vu des sites passer de 3 secondes à 0,5 seconde juste en configurant correctement les en-têtes. Et le plus beau, c'est que ça ne demande aucun changement de code.
Prenons un exemple concret. Sur un projet récent, j'ai ajouté Cache-Control: public, max-age=31536000 sur les images et les CSS. Le temps de chargement moyen est passé de 2,8s à 0,9s. Sans toucher au code, juste en configurant des en-têtes. C'est ça, la puissance du cache HTTP. Si tu ne le fais pas, tu laisses de la performance sur la table.
Maîtriser l'en-tête Cache-Control
Cache-Control est l'en-tête le plus puissant du cache HTTP. Il remplace les anciens Expires et Pragma. Avec lui, tu contrôles exactement qui va mettre en cache, pendant combien de temps, et comment revalider. C'est le levier de performance le plus rentable que tu puisses configurer.
Les directives clés : max-age définit la durée de vie en secondes. public autorise le cache partagé (CDN, proxys), private le limite au navigateur. no-cache force la revalidation avant chaque utilisation, no-store interdit toute mise en cache. must-revalidate oblige le serveur à vérifier si la ressource est toujours valide après expiration.
Concrètement, sur mes projets, je configure les ressources statiques comme ça : Cache-Control: public, max-age=31536000, immutable pour les images, CSS et JS versionnés. Pour les pages HTML dynamiques, j'utilise Cache-Control: no-cache, must-revalidate pour que le navigateur revalide à chaque requête. Résultat : le temps de chargement passe de 2,8s à 0,9s, sans toucher au code.
N'oublie pas s-maxage pour les caches partagés. Si tu utilises un CDN, cette directive lui donne une durée de vie différente de celle du navigateur. C'est un détail qui change tout quand tu as du trafic mondial.
Validation et revalidation : ETags et Last-Modified
Les ETags, c'est le truc que tout le monde ignore jusqu'au jour où tu te prends une revalidation inutile. Last-Modified, c'est bien, mais ça repose sur une date. Et les dates, ça ment. Un fichier peut changer sans que sa date bouge (si tu le régénères avec le même contenu, ou si ton serveur a un timestamp approximatif). L'ETag, lui, c'est un hash du contenu. Si le contenu change, le hash change. Point final.
Concrètement, quand le navigateur a une ressource en cache et qu'elle expire, il envoie une requête conditionnelle. Avec Last-Modified, il envoie If-Modified-Since. Avec un ETag, il envoie If-None-Match. Le serveur compare et répond soit 304 Not Modified (pas de transfert de données), soit 200 avec le nouveau contenu. J'ai vu des sites économiser 80% de bande passante juste en passant de Last-Modified à ETag, parce que les dates étaient souvent fausses.
Mon conseil : utilise les deux. Configure ton serveur pour générer un ETag fort (basé sur le contenu) et garde Last-Modified pour la compatibilité. Mais ne te fie jamais à Last-Modified seul. Sur un projet, j'ai eu un bug où le serveur renvoyait la même date pour des fichiers différents — résultat : le navigateur ne revalidait jamais et servait des versions périmées. L'ETag a réglé ça en une ligne de config. Si tu veux un cache fiable, l'ETag est ton meilleur ami.
Configurer le cache pour les ressources statiques et dynamiques, et aller plus loin avec les Service Workers
Commençons par les ressources statiques : images, CSS, JS. Pour moi, c'est simple : Cache-Control: public, max-age=31536000, immutable. Une année de cache, et immutable pour dire au navigateur de ne même pas revalider. Sur un de mes projets, j'ai appliqué ça aux images et aux polices : le nombre de requêtes a chuté de 80% dès le premier chargement. Le navigateur garde tout et ne redemande rien tant que le fichier n'a pas changé de nom.
Pour les ressources dynamiques, c'est une autre paire de manches. Tu ne veux pas que l'utilisateur voie une version périmée de ta page. Ma stratégie : Cache-Control: no-cache avec un ETag. Le navigateur stocke la réponse, mais doit la revalider à chaque fois. C'est un aller-retour serveur, mais le serveur répond 304 si rien n'a bougé. J'ai vu des sites économiser 90% de bande passante sur les pages HTML avec cette config. Le ETag est plus fiable que Last-Modified, car il est basé sur le contenu, pas sur la date.
Maintenant, les Service Workers. C'est un script qui s'exécute dans le navigateur et intercepte toutes les requêtes. Tu peux mettre en cache des ressources, même hors ligne. Concrètement, je crée un fichier sw.js et je l'enregistre avec navigator.serviceWorker.register('/sw.js'). Dans le script, j'écoute l'événement fetch et je réponds avec le cache ou le réseau.
Ce code basique suffit pour mettre en cache toutes les ressources après la première visite. Pour les ressources dynamiques, tu peux faire une stratégie réseau d'abord : vérifier le réseau, puis mettre à jour le cache. Attention, les Service Workers ne marchent qu'en HTTPS, et il faut gérer leur mise à jour avec un versionnage. Sinon, tu te retrouves avec un script obsolète qui casse tout.
Mon avis : commence par les en-têtes, c'est le plus rentable. Ajoute ensuite un Service Worker pour le mode hors-ligne et les performances avancées. Les deux se complètent, mais ne les confonds pas. Le cache HTTP est géré par le navigateur, le Service Worker te donne le contrôle total. Teste d'abord avec les en-têtes, mesure, puis ajoute le Service Worker si tu en as besoin.
Conclusion
Le cache HTTP, c'est le levier de performance le plus rentable que tu connaîtras. J'ai vu des sites passer de 3 secondes à 0,5 seconde sans toucher au code, juste en configurant des en-têtes. Si tu retiens une seule chose de cet article, c'est que Cache-Control, ETags et Last-Modified sont tes meilleurs amis.
Cache-Control orchestre tout : max-age pour la durée, public/private pour qui peut mettre en cache, no-cache pour forcer la validation. Les ETags et Last-Modified, c'est la validation fine : tu évites de re-télécharger ce qui n'a pas changé. Pour les ressources statiques, un max-age long avec un versioning dans l'URL. Pour le dynamique, no-cache avec validation. Et les Service Workers, c'est la cerise sur le gâteau : tu contrôles le cache côté client, tu gères l'offline, tu offres une expérience de folie.
Mon conseil : commence par les images et les CSS. Ajoute Cache-Control: public, max-age=31536000 et observe. Tu vas voir la différence. Le cache HTTP, c'est pas sorcier, c'est juste des règles que trop de devs ignorent. Configure-le, et tu gagnes des secondes sur chaque page. Fais-le maintenant.