304 Not Modified
Verwendung
Der Statuscode 304 Not Modified wird gesendet, wenn die Anfrage sicher ist, etwa eine GET- oder HEAD-Anfrage, und der Server feststellt, dass sich die Ressource gegenüber der im Cache des Clients gespeicherten Version nicht geändert hat. Das spart Bandbreite, da der Server keine Daten erneut überträgt, die der Client bereits besitzt.
Hinweis
304 Not Modified ist keine Weiterleitung, auch wenn der Code zur Statusklasse 3xx gehört. Weiterleitungen (301, 302, 307, 308) schicken den Client über den Location-Header zu einer anderen URL. 304 weist den Client an, seine zwischengespeicherte Kopie derselben Ressource wiederzuverwenden, und es wird kein Location-Header gesendet. Die Browser-DevTools fassen 304 mitunter mit Weiterleitungen zusammen, was zusätzlich zur Verwirrung beiträgt.
Hinweis
“200 (from disk cache)” in den DevTools bedeutet, dass der Browser die Ressource aus dem Cache ausgeliefert hat, ohne den Server zu kontaktieren, weil die Cache-Control-Angabe max-age noch nicht abgelaufen ist. 304 bedeutet, dass der Browser den Server zur Neuvalidierung kontaktiert hat und der Server bestätigt hat, dass die zwischengespeicherte Kopie aktuell ist. Ein zwischengespeichertes 200 verursacht keinerlei Netzwerkanfragen, während ein 304 einen Roundtrip erfordert.
Der Server erzeugt in der Antwort einen oder mehrere der folgenden Header:
Da das Ziel der Antwort 304 Not Modified die Minimierung der Bandbreite ist, lässt der Server Header weg, die nicht in der ursprünglichen Anfrage enthalten waren, sofern sie nicht dem Cache-Aktualisierungsprozess dienen.
Bei bedingten GET-Anfragen sind die Direktiven If-None-Match und If-Modified-Since maßgeblich. Sie stützen sich auf einen Validator wie ETag, um zu beurteilen, ob die Ressource erneut übertragen werden muss.
Beispiel
Der Client fordert eine Ressource an, erhält ein ETag, das die Version kennzeichnet, und validiert sie später erneut. Der Server erkennt, dass die Ressource unverändert ist, und gibt 304 Not Modified zurück. Bei der dritten Anfrage liegt eine neue Version vor, und es wird eine vollständige 200-Antwort mit aktualisiertem ETag gesendet.
Hinweis
Jedes Mal, wenn der Server eine Ressource aktualisiert, wird ein neues ETag erzeugt. Alternativ gibt der Server ein Last-Modified-Datum zurück, und der Client verwendet stattdessen If-Modified-Since, womit sich das Pflegen einer ETag-Historie auf dem Server erübrigt.
SEO-Auswirkung
Erhält Googlebot ein 304, erkennt der Crawler, dass sich der Inhalt seit dem letzten Crawl nicht geändert hat. Die Indexierungs-Pipeline berechnet die Ranking-Signale für die URL neu, ruft den Inhalt jedoch nicht erneut ab und indexiert ihn nicht erneut.
Die Falle des veralteten 304
Ein 304 bestätigt, dass die zwischengespeicherte Version noch aktuell ist. Wenn der Server zuvor eine defekte Seite (leerer Body, Fehlerinhalt) mit einem 200 ausgeliefert hat und der Crawler das Ergebnis zwischengespeichert hat, teilt ein nachfolgendes 304 dem Crawler mit, dass die defekte Version weiterhin besteht. Der Crawler hört auf, erneut zu prüfen, weil sich der “Inhalt” nicht geändert hat. Die Seite allein zu reparieren genügt nicht. Der Server muss ein frisches 200 mit dem korrigierten Body (und einem neuen ETag) zurückgeben, um den zwischengespeicherten Fehler zu ersetzen. Dieses Szenario ist schwer zu debuggen, weil die eigentliche Ursache (ein vergangener vorübergehender Fehler) nicht mehr sichtbar ist.
Erste Anfrage
GET /news.html HTTP/1.1
Host: example.com
Erste Antwort
HTTP/1.1 200 OK
ETag: "1234000"
Content-Type: text/html
Content-Length: 1250
<message body contains requested resource>
Zweite Anfrage
GET /news.html HTTP/1.1
Host: example.com
If-None-Match: "1234000"
Zweite Antwort
HTTP/1.1 304 Not Modified
ETag: "1234000"
Dritte Anfrage
GET /news.html HTTP/1.1
Host: example.com
If-None-Match: "1234000"
Dritte Antwort
HTTP/1.1 200 OK
ETag: "1234001"
Content-Type: text/html
Content-Length: 1600
<message body contains requested resource>
Code-Referenzen
.NET
HttpStatusCode.NotModified
Rust
http::StatusCode::NOT_MODIFIED
Rails
:not_modified
Go
http.StatusNotModified
Symfony
Response::HTTP_NOT_MODIFIED
Python3.5+
http.HTTPStatus.NOT_MODIFIED
Java
java.net.HttpURLConnection.HTTP_NOT_MODIFIED
Apache HttpComponents Core
org.apache.hc.core5.http.HttpStatus.SC_NOT_MODIFIED
Angular
@angular/common/http/HttpStatusCode.NotModified