HTTP 304 Not Modified : ETag et If-None-Match expliqués | We.Inc
Simulez une requête conditionnelle : définissez l'ETag et le Last-Modified du serveur, les If-None-Match et If-Modified-Since du navigateur, et voyez 304 ou 200 avec la raison.
Une réponse 304 Not Modified indique au navigateur que sa copie en cache est toujours à jour : le serveur n'a donc pas besoin de renvoyer le corps. Elle répond à un GET ou HEAD conditionnel qui portait If-None-Match ou If-Modified-Since. Un 304 est une bonne nouvelle, pas une erreur : il économise de la bande passante tandis que le fichier en cache continue d'être utilisé.
Les paires de validateurs derrière un 304
Le serveur envoie
Le navigateur renvoie
Le serveur répond 304 quand
ETag: "v2"
If-None-Match: "v2"
Un des tags listés correspond à l'ETag actuel (comparaison faible)
Last-Modified: <date>
If-Modified-Since: <date>
La ressource n'a pas changé depuis cette date
Les deux
Les deux
If-None-Match décide ; If-Modified-Since est ignoré
Indiquez ce que le serveur détient actuellement et ce que le navigateur envoie, et le simulateur applique les règles de priorité de la spécification HTTP. Il affiche le statut que le serveur doit renvoyer et l'en-tête qui l'a déterminé. Videz un champ pour omettre cet en-tête.
Définissez l'ETag et le Last-Modified que le serveur possède pour le fichier en ce moment.
Définissez les en-têtes If-None-Match et If-Modified-Since que le navigateur envoie depuis son cache.
Lisez le statut et la raison : quel en-tête a été évalué et pourquoi il correspond ou non.
Modifiez l'ETag du serveur pour voir comment un déploiement transforme la requête suivante en 200.
Un 304 doit répéter les en-têtes comme Cache-Control, ETag, Vary et Date qu'un 200 porterait, pour que le cache puisse rafraîchir ses métadonnées stockées.
Des noms de fichiers avec empreinte comme app.3f9a1c.js et un long max-age évitent complètement la revalidation. Réservez la revalidation par ETag au HTML et aux réponses d'API.
Les ETags faibles commencent par W/ et promettent une équivalence sémantique, pas une égalité octet par octet. Ils fonctionnent quand même avec If-None-Match, car cet en-tête utilise la comparaison faible.
Dans les DevTools, une ligne 304 avec une petite taille de transfert signifie que le navigateur a revalidé avec succès. Désactivez le cache dans le panneau Network pour forcer des réponses 200 complètes pendant le débogage.
Questions fréquentes
Une réponse 304 est-elle une erreur ?
Non. C'est un statut de la classe redirection qui signifie que la copie en cache peut être utilisée. Le navigateur affiche la page depuis son cache, et seuls les en-têtes ont transité sur le réseau.
Une réponse 304 peut-elle avoir un corps ?
Non. La spécification indique qu'une réponse 304 se termine à la fin de la section des en-têtes et ne peut pas contenir de contenu.
Lequel l'emporte, If-None-Match ou If-Modified-Since ?
If-None-Match. Quand une requête porte les deux, un serveur qui prend en charge les entity tags évalue If-None-Match et ignore If-Modified-Since, car les tags détectent des changements qu'une date à la seconde près ne voit pas.
Pourquoi ai-je un 200 au lieu d'un 304 après chaque déploiement ?
Le déploiement a modifié le fichier ou son ETag, donc le tag que détient le navigateur ne correspond plus. C'est le comportement attendu. Si des fichiers inchangés perdent aussi leur 304, vérifiez si vos serveurs génèrent des ETags différents pour un même contenu.
Un POST renvoie-t-il parfois un 304 ?
Non. If-None-Match et If-Modified-Since ne produisent un 304 que pour GET et HEAD. Pour les autres méthodes, une condition non remplie donne 412 Precondition Failed.
Comment fonctionne la revalidation
Quand une réponse en cache devient périmée, le navigateur ne la jette pas. Il demande au serveur si sa copie est toujours valable en envoyant les validateurs qu'il a gardés : l'ETag dans If-None-Match, la date Last-Modified dans If-Modified-Since.
Si rien n'a changé, le serveur répond 304 avec des en-têtes frais et sans corps, et le navigateur continue d'utiliser sa copie. Si quelque chose a changé, le serveur envoie un 200 normal avec le nouveau contenu.
Tags forts et faibles
Un tag fort comme "v2" garantit que les octets sont identiques. Un tag faible comme W/"v2" garantit seulement que le contenu est équivalent. If-None-Match compare de façon faible, donc W/"v2" et "v2" y comptent comme une correspondance ; If-Match compare de façon forte et ne les considérerait pas comme égaux.
L'échange sur le réseau
Première visite : 200 avec validateurs
Le serveur fournit un ETag et une date Last-Modified avec le contenu.
Visite suivante : 304 sans corps
Le navigateur renvoie le tag sauvegardé et ne reçoit que des en-têtes.
Répondre vous-même aux requêtes conditionnelles
Serveur http Node avec un ETag basé sur un hash du contenu
Calcule le hash du corps, le compare à If-None-Match et envoie un 304 sans corps en cas de correspondance.
Simulateur de requête conditionnelle
Ce que le serveur détient maintenant
Ce que le navigateur envoie
ETag
Last-Modified
If-None-Match
If-Modified-Since
Réponse du serveur
If-None-Match liste un tag qui correspond à l'ETag actuel en comparaison faible, donc la copie en cache est à jour.
If-None-Match vaut * et la ressource existe, donc la condition est fausse.
Aucun tag de If-None-Match ne correspond à l'ETag actuel, donc le serveur envoie le nouveau contenu. If-Modified-Since n'est pas vérifié.
Il n'y a pas de If-None-Match, et Last-Modified n'est pas postérieur à If-Modified-Since.
Il n'y a pas de If-None-Match, et Last-Modified est postérieur à If-Modified-Since.
If-Modified-Since est présent mais l'une des deux dates est illisible, donc l'en-tête est ignoré.
La requête n'a pas de validateurs, c'est donc une requête ordinaire.