Cache navigateur et cache serveur : tout comprendre

Dans cet article

  • Le cache navigateur peut réduire le temps de chargement d’une page de 40 à 70 % lors des visites suivantes
  • Un cache serveur correctement configuré diminue la charge CPU du serveur de 50 à 80 % selon l’infrastructure
  • Les en-têtes Cache-Control et ETag sont les deux mécanismes fondamentaux à maîtriser côté HTTP
  • WordPress dispose de 5 niveaux de cache empilables : navigateur, page, objet, opcode et CDN
  • Une stratégie de cache mal calibrée peut servir du contenu obsolète pendant des heures sans que vous le remarquiez
  • Le temps de configuration optimal se situe entre 1 et 3 heures pour un site WordPress standard

Depuis que je développe des sites web, la question du cache revient dans chaque projet sans exception. Un client me contacte parce que son site met quatre secondes à charger, un autre ne comprend pas pourquoi sa modification n’apparaît pas en ligne. À chaque fois, la réponse tourne autour du même sujet : le cache. Pourtant, quand je demande à mes clients s’ils savent ce que fait réellement le cache de leur site, la réponse est presque toujours la même : « C’est un truc qu’on vide quand ça ne marche pas. »

Je vais vous expliquer concrètement comment fonctionnent le cache navigateur et le cache serveur, pourquoi ils sont complémentaires, et surtout comment les configurer pour que votre site soit rapide sans jamais servir de contenu périmé. Pas de jargon inutile : des explications claires, des configurations que j’utilise en production, et les erreurs que je vois le plus souvent chez mes clients.

Qu’est-ce que le cache web et pourquoi s’en préoccuper

Le cache web est un mécanisme de stockage temporaire qui conserve une copie des ressources (pages HTML, images, fichiers CSS, scripts JavaScript) pour les resservir plus rapidement lors des requêtes suivantes. Au lieu de recalculer ou retélécharger une ressource à chaque visite, le système la récupère depuis un emplacement plus proche de l’utilisateur.

Pour comprendre l’enjeu, il faut visualiser ce qui se passe quand un visiteur charge une page sans aucun cache. Le navigateur envoie une requête au serveur, qui interroge la base de données, exécute le code PHP, assemble le HTML, puis renvoie le tout avec les fichiers CSS, JavaScript et les images. Ce processus peut générer entre 20 et 80 requêtes HTTP pour une seule page. Multipliez ça par 500 visiteurs simultanés et votre serveur commence à souffrir.

Le cache intervient à plusieurs niveaux de cette chaîne pour court-circuiter les étapes les plus coûteuses. C’est exactement comme la mémoire tampon de votre cerveau : vous ne recalculez pas 7 × 8 à chaque fois, vous savez que c’est 56. Le cache fonctionne sur le même principe, appliqué aux ressources web.

Selon les données publiées par la documentation Mozilla sur le cache HTTP, un cache bien configuré peut réduire la latence perçue de 40 à 70 % et diminuer significativement la bande passante consommée. C’est un levier direct sur l’amélioration de la vitesse de votre site.

L'onglet Network des DevTools permet de vérifier le bon fonctionnement du cache navigateur
L’onglet Network des DevTools permet de vérifier le bon fonctionnement du cache navigateur

Cache navigateur : fonctionnement détaillé

Le cache navigateur (ou cache client) est le premier niveau de cache que rencontre un visiteur. Il stocke les ressources directement sur l’ordinateur ou le téléphone de l’utilisateur, dans un espace dédié du navigateur (Chrome, Firefox, Safari, Edge).

Quand vous visitez un site pour la première fois, le navigateur télécharge toutes les ressources nécessaires. Lors de votre deuxième visite, au lieu de tout retélécharger, il vérifie d’abord son cache local. Si les fichiers y sont et qu’ils n’ont pas expiré, il les utilise sans même contacter le serveur. C’est ce qu’on appelle un « cache hit » et c’est quasi instantané.

Les deux modes de validation du cache navigateur

Le cache navigateur fonctionne selon deux logiques distinctes que je configure systématiquement sur les sites de mes clients :

Le cache fort (freshness) : le serveur dit au navigateur « cette ressource est valable pendant X secondes, ne me redemande rien avant ». C’est l’en-tête Cache-Control: max-age=31536000 qui gère ça. Pendant toute cette durée, le navigateur n’envoie aucune requête au serveur pour cette ressource. C’est le mécanisme le plus performant.

Le cache conditionnel (validation) : le navigateur contacte le serveur pour demander « est-ce que cette ressource a changé depuis la dernière fois ? ». Le serveur répond soit « non, utilise ta copie » (réponse 304 très légère), soit « oui, voici la nouvelle version ». Ce mécanisme utilise les en-têtes ETag et Last-Modified.

En pratique, j’utilise le cache fort pour les ressources statiques (CSS, JS, images, polices) avec des durées longues, et le cache conditionnel pour les pages HTML qui changent plus souvent. Cette distinction est essentielle pour ne pas servir de pages erronnées ou obsolètes à vos visiteurs.

Ce que stocke réellement le navigateur

Le cache navigateur conserve : les fichiers HTML, CSS et JavaScript, les images et favicons, les polices web (WOFF2), les réponses d’API si les en-têtes le permettent, et même certains résultats DNS. Sur Chrome, vous pouvez voir le contenu du cache en tapant chrome://cache dans la barre d’adresse. La taille du cache varie selon les navigateurs, mais elle tourne autour de 250 Mo à 1 Go par site sur les navigateurs modernes.

Cache serveur : fonctionnement et types

Le cache serveur opère du côté de votre hébergement. Son rôle est de réduire le travail que le serveur doit fournir pour générer une page. Contrairement au cache navigateur qui profite à un seul utilisateur, le cache serveur bénéficie à tous les visiteurs simultanément.

Le cache de page (full-page cache)

C’est le plus impactant. Au lieu d’exécuter PHP et d’interroger la base de données MySQL à chaque visite, le serveur stocke le HTML final de la page. Quand un visiteur arrive, le serveur renvoie directement ce HTML statique. Le temps de réponse passe typiquement de 800 ms à moins de 50 ms. Sur WordPress, c’est ce que font WP Super Cache, W3 Total Cache ou WP Rocket.

Le cache objet (object cache)

Ce niveau de cache stocke les résultats des requêtes à la base de données. WordPress utilise un système d’object cache intégré, mais par défaut il ne persiste que pendant le chargement d’une page. En ajoutant Redis ou Memcached, les résultats sont conservés en mémoire vive entre les requêtes. C’est particulièrement utile pour les sites WooCommerce ou les sites avec beaucoup de contenu dynamique où le full-page cache n’est pas toujours possible.

Le cache opcode (OPcache)

PHP est un langage interprété : à chaque requête, le serveur doit compiler le code PHP en bytecode avant de l’exécuter. OPcache stocke ce bytecode compilé en mémoire, éliminant l’étape de compilation. C’est une optimisation transparente qui apporte un gain de 20 à 30 % sur le temps d’exécution PHP. Sur la plupart des hébergeurs sérieux, OPcache est activé par défaut.

Le cache CDN

Un CDN (Content Delivery Network) réplique vos ressources sur des serveurs répartis géographiquement. Un visiteur à Marseille récupère les fichiers depuis un serveur à Paris plutôt que depuis un datacenter à Montréal. Le gain en latence est immédiat : 30 à 200 ms de moins selon la distance. Cloudflare, par exemple, propose un cache CDN gratuit qui couvre la majorité des besoins. Cette approche est complémentaire des générateurs de sites statiques qui produisent des fichiers directement distribuables via CDN.

Le cache serveur et le CDN travaillent ensemble pour servir les pages au plus proche de l'utilisateur
Le cache serveur et le CDN travaillent ensemble pour servir les pages au plus proche de l’utilisateur

Différences clés entre cache navigateur et cache serveur

La confusion entre ces deux types de cache est la source de la majorité des problèmes que je rencontre chez mes clients. Voici un comparatif clair pour comprendre ce qui les distingue.

CritèreCache navigateurCache serveur
EmplacementAppareil de l’utilisateurServeur d’hébergement ou CDN
PortéeUn seul utilisateurTous les visiteurs
ContrôleEn-têtes HTTP envoyés par le serveurConfiguration serveur (plugin, .htaccess, Nginx)
PurgeL’utilisateur vide son cache ou le cache expireL’administrateur purge manuellement ou automatiquement
Gain principalZéro requête réseau (instantané)Zéro exécution PHP/SQL (réponse ultra-rapide)
Risque principalContenu obsolète affiché à un utilisateurContenu obsolète affiché à tous les visiteurs
Impact SEOIndirect (Core Web Vitals)Direct (TTFB, temps de réponse serveur)
Durée typique1 an pour les assets statiques1 à 24 heures pour les pages HTML

Le point essentiel à retenir : ces deux caches sont complémentaires, pas interchangeables. Le cache serveur accélère la première visite de chaque page pour tous les utilisateurs. Le cache navigateur accélère les visites suivantes pour un même utilisateur. Désactiver l’un ou l’autre, c’est se priver de la moitié du gain de performance. Cela a un impact direct sur l’expérience utilisateur et le taux de rebond.

Les en-têtes HTTP qui contrôlent le cache

Le cache web repose entièrement sur les en-têtes HTTP. Ce sont des métadonnées envoyées avec chaque réponse du serveur qui indiquent au navigateur (et aux caches intermédiaires) comment traiter la ressource. Voici les en-têtes que je configure sur chaque projet.

Cache-Control

C’est l’en-tête principal, le plus puissant et le plus utilisé. Il accepte plusieurs directives combinables :

Cache-Control: public, max-age=31536000, immutable signifie : cette ressource peut être mise en cache par tous (navigateur et CDN), elle est valable pendant un an, et elle ne changera jamais. C’est la configuration idéale pour les fichiers CSS et JS versionnés (avec un hash dans le nom de fichier).

Cache-Control: no-cache ne signifie pas « ne pas mettre en cache ». Ça signifie « mets en cache mais revalide à chaque fois ». C’est une confusion fréquente. Pour interdire totalement le cache, il faut utiliser Cache-Control: no-store.

Cache-Control: private, max-age=0, must-revalidate est ce que j’utilise pour les pages contenant des données personnelles (panier WooCommerce, espace client). Private interdit au CDN de mettre en cache, seul le navigateur de l’utilisateur peut le faire.

ETag et Last-Modified

Ces en-têtes permettent la validation conditionnelle. Le serveur envoie un ETag (une empreinte unique du fichier) ou une date Last-Modified. Lors de la requête suivante, le navigateur renvoie cette information. Si le fichier n’a pas changé, le serveur répond 304 Not Modified sans renvoyer le contenu, économisant de la bande passante. Selon les recommandations de Google sur la mise en cache HTTP (web.dev), combiner ETag avec Cache-Control offre la meilleure couverture possible.

Vary

L’en-tête Vary indique que la réponse peut différer selon certains paramètres de la requête. Vary: Accept-Encoding est le plus courant : il dit au cache que la version gzippée et la version non compressée sont des réponses différentes. Sans cet en-tête, un CDN pourrait servir une version compressée à un navigateur qui ne supporte pas la compression.

Mettre en place une stratégie de cache sur WordPress

WordPress, sans cache, exécute entre 20 et 50 requêtes SQL et des dizaines de fichiers PHP pour générer une seule page. Avec 12 ans de pratique sur ce CMS, voici la stratégie que je déploie systématiquement.

Niveau 1 : le cache de page

J’installe un plugin de cache de page en priorité. WP Rocket est mon choix par défaut pour les clients qui veulent une solution simple. Pour les projets où je veux un contrôle total, j’utilise Nginx FastCGI Cache directement au niveau du serveur, ce qui est encore plus performant car PHP n’est même pas sollicité. Le TTFB (Time To First Byte) passe typiquement de 600-1200 ms à moins de 100 ms.

Niveau 2 : le cache objet avec Redis

Pour les sites avec du contenu dynamique (WooCommerce, espaces membres, forums), j’ajoute Redis comme backend d’object cache. L’installation prend 15 minutes : installer Redis sur le serveur, ajouter le plugin Redis Object Cache sur WordPress, et c’est opérationnel. Les requêtes SQL répétitives sont servies depuis la mémoire vive en moins de 1 ms au lieu de 5 à 20 ms depuis MySQL.

Niveau 3 : les en-têtes navigateur via .htaccess

Je configure les en-têtes de cache navigateur directement dans le fichier .htaccess pour Apache, ou dans le bloc server pour Nginx. Voici la configuration que j’utilise en production :

# Cache navigateur - fichiers statiques
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType image/webp "access plus 1 year"
  ExpiresByType text/css "access plus 1 year"
  ExpiresByType application/javascript "access plus 1 year"
  ExpiresByType font/woff2 "access plus 1 year"
</IfModule>

# En-têtes Cache-Control
<IfModule mod_headers.c>
  <FilesMatch "\.(css|js|woff2|png|jpg|webp|svg)$">
    Header set Cache-Control "public, max-age=31536000, immutable"
  </FilesMatch>
  <FilesMatch "\.(html|htm)$">
    Header set Cache-Control "no-cache, must-revalidate"
  </FilesMatch>
</IfModule>

Cette configuration applique un cache d’un an sur les fichiers statiques et force la revalidation sur les pages HTML. Pour que les mises à jour CSS/JS soient prises en compte malgré le cache long, j’utilise le cache busting : le nom du fichier inclut un hash qui change à chaque modification (par exemple style.a3f7b2.css). C’est un point à vérifier lors de toute refonte de site web.

Niveau 4 : le CDN

En dernier, j’ajoute Cloudflare en mode proxy. Le plan gratuit suffit pour 90 % des sites. Cloudflare met en cache les ressources statiques sur ses 300+ points de présence mondiaux et ajoute une couche de protection contre les attaques DDoS. Pour les sites dont l’audience est principalement française, le gain est modéré (les serveurs OVH sont déjà en France), mais pour un site international, c’est indispensable.

La commande curl permet de vérifier rapidement les en-têtes de cache HTTP de n'importe quelle URL
La commande curl permet de vérifier rapidement les en-têtes de cache HTTP de n’importe quelle URL

Cas pratiques : configurer le cache pas à pas

Cas 1 : un site vitrine WordPress classique

Pour un site vitrine de 10 à 30 pages qui change peu, voici ma configuration standard. J’installe WP Rocket, j’active le cache de page avec une durée de 24 heures, j’active la précharge du cache (WP Rocket visite automatiquement chaque page pour générer le cache), et je configure les en-têtes navigateur comme indiqué plus haut. Ce type de site peut tourner sur un hébergement mutualisé à 5 € par mois sans problème avec cette configuration. Le résultat : un score PageSpeed de 90+ sur mobile.

Cas 2 : un site e-commerce WooCommerce

WooCommerce complique la donne car certaines pages sont dynamiques par nature : le panier, le tunnel de commande, le compte client. Ma stratégie : cache de page pour les fiches produits et les pages catégories (durée de 12 heures), exclusion du cache pour /cart/, /checkout/ et /my-account/, Redis pour l’object cache (les requêtes produits sont souvent identiques), et Cache-Control: private sur les pages exclues pour que le CDN ne les mette jamais en cache.

Cas 3 : un site avec contenu en temps réel

Pour un site d’actualités ou un tableau de bord, j’utilise la stratégie stale-while-revalidate. L’en-tête Cache-Control: max-age=60, stale-while-revalidate=300 signifie : le contenu est frais pendant 60 secondes. Après ça, sers le contenu périmé immédiatement tout en récupérant la nouvelle version en arrière-plan. L’utilisateur ne voit jamais de temps de chargement, et le contenu est rafraîchi en moins de 5 minutes.

Erreurs fréquentes et comment les éviter

En 12 ans de métier, j’ai vu les mêmes erreurs revenir chez des dizaines de clients. Voici celles qui causent le plus de dégâts.

Erreur n°1 : cacher les pages d’administration. WordPress exclut normalement /wp-admin/ du cache, mais certains plugins ou configurations Nginx mal réglés mettent tout en cache. Résultat : vous vous connectez et voyez le tableau de bord d’un autre administrateur. C’est un problème de sécurité grave.

Erreur n°2 : mettre un cache long sur le HTML sans cache busting. Si vous mettez max-age=86400 sur vos pages HTML et que vous modifiez un article, les visiteurs qui ont la page en cache ne verront pas la modification pendant 24 heures. Pour le HTML, préférez toujours no-cache avec un ETag.

Erreur n°3 : empiler les plugins de cache. J’ai déjà trouvé trois plugins de cache actifs simultanément sur un même site. WP Super Cache, W3 Total Cache et LiteSpeed Cache se marchaient dessus, générant des conflits qui faisaient planter le site aléatoirement. Un seul plugin de cache de page suffit.

Erreur n°4 : ne jamais purger le cache. Après une mise à jour de contenu, de thème ou de plugin, il faut purger le cache. La plupart des plugins le font automatiquement, mais pas tous. Si votre modification n’apparaît pas, c’est la première chose à vérifier avant de penser à un problème de redirection 301 ou 302.

Erreur n°5 : oublier le cache sur les appareils mobiles. Certains sites servent une version différente pour mobile et desktop. Si le cache ne tient pas compte du User-Agent (via l’en-tête Vary), un visiteur mobile peut recevoir la version desktop en cache, ou inversement.

Erreur n°6 : confondre no-cache et no-store. Je l’ai mentionné plus haut, mais c’est tellement courant que ça mérite d’être répété. no-cache autorise le stockage avec revalidation obligatoire. no-store interdit tout stockage. Pour des données sensibles (formulaires de paiement, données personnelles en conformité avec le RGPD), utilisez toujours no-store.

Outils pour auditer et valider votre cache

Configurer le cache c’est bien, mais vérifier qu’il fonctionne correctement c’est indispensable. Voici les outils que j’utilise au quotidien.

Les DevTools du navigateur (onglet Network) : c’est mon premier réflexe. Ouvrez les DevTools (F12), allez dans l’onglet Network, rechargez la page. La colonne « Size » indique « disk cache » ou « memory cache » quand la ressource est servie depuis le cache navigateur. La colonne « Status » montre 304 pour une revalidation réussie. Vérifiez les en-têtes de réponse de chaque ressource pour confirmer que Cache-Control est bien présent.

Google PageSpeed Insights : l’outil de Google signale explicitement les ressources qui n’ont pas de politique de cache appropriée dans la section « Serve static assets with an efficient cache policy ». C’est un indicateur fiable pour identifier les oublis. Le score PageSpeed influence votre référencement et votre visibilité sur Google.

curl en ligne de commande : pour vérifier les en-têtes sans ouvrir un navigateur, j’utilise curl -I https://monsite.fr/page. La réponse affiche tous les en-têtes HTTP, y compris Cache-Control, ETag, X-Cache (qui indique si la réponse vient du CDN) et X-Cache-Status (HIT ou MISS).

WebPageTest : cet outil gratuit permet de tester le chargement depuis différentes localisations et avec différentes connexions. Il affiche un waterfall détaillé qui montre clairement quelles ressources sont mises en cache et lesquelles ne le sont pas. C’est particulièrement utile pour valider la configuration CDN.

GTmetrix : similaire à WebPageTest, avec une interface plus accessible. Il fournit des recommandations spécifiques sur le cache et permet de comparer les performances avant et après configuration. C’est l’outil que je recommande à mes clients pour qu’ils puissent surveiller leurs performances, au même titre que la vérification de leur fichier robots.txt et de leur sitemap XML.

Quand j’implémente le lazy loading des images en parallèle d’une stratégie de cache, les gains de performance se cumulent et le score PageSpeed monte souvent au-dessus de 95.

À retenir

  • Configurez Cache-Control: max-age=31536000, immutable sur tous vos fichiers CSS, JS, images et polices
  • Utilisez no-cache avec ETag sur les pages HTML pour garantir la fraîcheur du contenu
  • Installez un seul plugin de cache sur WordPress et ajoutez Redis pour l’object cache si votre site est dynamique
  • Vérifiez vos en-têtes avec curl -I ou les DevTools après chaque modification de configuration
  • Excluez toujours les pages sensibles du cache : panier, checkout, espace client, wp-admin

Questions fréquentes

Vider le cache du navigateur améliore-t-il les performances ?

Vider le cache navigateur force le retéléchargement de toutes les ressources, ce qui ralentit temporairement le chargement. C’est utile pour voir une modification récente ou résoudre un problème d’affichage, mais ce n’est pas une optimisation de performance. Au contraire, un cache navigateur bien rempli accélère la navigation de 40 à 70 %. Ne videz le cache que quand c’est nécessaire, pas de façon préventive.

Pourquoi est-il conseillé de vider régulièrement le cache du navigateur ?

Le cache peut accumuler des fichiers obsolètes ou corrompus qui provoquent des erreurs d’affichage. En pratique, les navigateurs modernes gèrent très bien l’expiration automatique grâce aux en-têtes HTTP. Je recommande de vider le cache uniquement quand un problème visuel persiste après un rechargement forcé (Ctrl+Shift+R), pas selon un calendrier régulier.

Quelles sont les 5 stratégies de mise en cache les plus efficaces ?

Les cinq stratégies que je déploie sont : le cache de page (HTML statique serveur), le cache objet (Redis/Memcached pour les requêtes SQL), le cache navigateur (en-têtes Cache-Control sur les assets), le cache CDN (distribution géographique via Cloudflare), et le cache opcode (OPcache pour le bytecode PHP). Empilées correctement, ces cinq couches couvrent toute la chaîne de requête.

Comment savoir si le cache de mon site fonctionne correctement ?

Ouvrez les DevTools de votre navigateur (F12), onglet Network, et rechargez la page. Les ressources servies depuis le cache affichent « disk cache » ou « memory cache » dans la colonne Size. Vous pouvez aussi utiliser curl -I votre-url pour vérifier les en-têtes Cache-Control et X-Cache. Un en-tête X-Cache: HIT confirme que le CDN sert le contenu depuis son cache.

Le cache peut-il poser des problèmes de sécurité ?

Oui, si des pages contenant des données personnelles sont mises en cache publiquement, d’autres utilisateurs peuvent y accéder. C’est pourquoi il faut utiliser Cache-Control: private, no-store sur les pages de compte client, de panier et de paiement. Un CDN mal configuré qui cache une page avec des informations de session est un risque sérieux. Vérifiez systématiquement que les pages sensibles sont exclues du cache.

Quelle est la différence entre Cache-Control no-cache et no-store ?

no-cache autorise le stockage de la ressource en cache mais oblige le navigateur à revalider auprès du serveur avant chaque utilisation. no-store interdit totalement le stockage : la ressource n’est jamais conservée, ni en mémoire ni sur disque. Pour les données sensibles (paiement, informations personnelles), utilisez toujours no-store. Pour du contenu public qui change souvent, no-cache avec un ETag est le bon choix.

Nathan Morel
Nathan Morel

Nathan Morel est développeur web freelance depuis 12 ans dans la Loire. Spécialisé WordPress et solutions sur mesure, il a accompagné plus de 200 PME et partage son expérience technique et entrepreneuriale sur NA Web.

Un projet web ? Discutons-en.

Diagnostic gratuit et devis sous 24h.

Me contacter

Votre site est lent ?

Optimiser mon site