HTTP-Caching ist ein Mechanismus im HTTP-Protokoll, der Browsern, CDNs und Proxy-Servern erlaubt, Kopien von Antworten zu speichern und für spätere Anfragen ohne Kontakt zum Origin-Server wiederzuverwenden. Es ist die wichtigste Performance-Technik im Web. Ein korrekt gecachtes statisches Asset (Bild, CSS, JS-Bundle) lädt in 1 bis 10 Millisekunden aus dem Browser-Cache statt 100 bis 1000 Millisekunden vom Origin. HTTP-Caching wird über Antwort-Header gesteuert, definiert in RFC 7234 (Juni 2014) und dem neueren RFC 9111 (Juni 2022): Cache-Control (primärer moderner Header), Expires (Legacy), ETag und Last-Modified (Validatoren) sowie Vary (Cache-Key-Modifier). Richtig eingesetzt verbessert HTTP-Caching den Largest Contentful Paint (LCP), spart Bandbreite (Google schätzt 60 bis 80 Prozent der typischen Website-Bandbreite sind cacheable), reduziert die Last des Origin-Servers und senkt den CO2-Fußabdruck. Falsch eingesetzt führt es zu veralteten Inhalten, kaputten Deploys und endlosen Reloads in Browser-Tabs.
Wie funktioniert HTTP-Caching?
Wenn ein Browser eine Ressource anfragt, kann die Antwort Cache-Anweisungen enthalten. Der Browser speichert die Antwort lokal. Bei der nächsten Anfrage für dieselbe URL prüft der Browser den Cache:
- Ist die Kopie noch frisch (innerhalb ihrer TTL), nutzt der Browser sie direkt ohne Netzwerkanfrage. Das ist ein Cache Hit.
- Ist die Kopie veraltet, aber hat einen Validator (ETag oder Last-Modified), sendet der Browser eine Conditional Request mit
If-None-MatchoderIf-Modified-Since. Der Server antwortet mit304 Not Modifiedohne Body, wenn die Ressource sich nicht geändert hat, und spart Bandbreite. - Gibt es keinen Validator und die Kopie ist veraltet, lädt der Browser die volle Ressource neu (Cache Miss).
Zwischen Browser und Origin liegen meist ein oder mehrere Shared Caches (CDN-Edge-Knoten, Unternehmens-Proxies). Dieselben Regeln gelten auf jeder Ebene.
Was macht Cache-Control?
Cache-Control ist der primäre Header zur Steuerung des Cache-Verhaltens. Er nimmt eine kommagetrennte Liste von Direktiven entgegen:
| Direktive | Bedeutung |
|---|---|
max-age=N | Antwort ist N Sekunden frisch. |
s-maxage=N | Wie max-age, gilt aber nur für Shared Caches (CDN, Proxy). Überschreibt dort max-age. |
public | Jeder Cache darf speichern. |
private | Nur der Browser darf speichern, kein Shared Cache. Für personalisierte Inhalte. |
no-cache | Speichern erlaubt, aber bei jeder Wiederverwendung mit Origin revalidieren. |
no-store | Niemals speichern. Für wirklich sensible Daten (Banking, Gesundheit). |
must-revalidate | Nach Ablauf muss der Cache prüfen und darf bei Fehler keine veraltete Kopie liefern. |
stale-while-revalidate=N | Nach Ablauf darf bis zu N Sekunden veraltet ausgeliefert werden, während im Hintergrund revalidiert wird. Großer UX-Gewinn. |
stale-if-error=N | Bei 5xx vom Origin bis zu N Sekunden veraltet ausliefern. |
immutable | Die Antwort ändert sich nie. Der Browser überspringt selbst beim Reload die Validierung. |
Praktische Beispiele:
# Fingerprintetes statisches Asset (app.abc123.js)
Cache-Control: public, max-age=31536000, immutable
# HTML-Seite, immer frisch, aber kurze Revalidierung erlaubt
Cache-Control: public, max-age=0, s-maxage=300, stale-while-revalidate=86400
# Personalisierte Kontoseite
Cache-Control: private, no-cache
# Login-Formular
Cache-Control: no-storeWas ist ein ETag?
Ein ETag (Entity Tag) ist ein opaker Identifier, den der Server an eine Antwort anhängt, um eine bestimmte Version der Ressource zu identifizieren. Bei einer Conditional Request sendet der Client den ETag-Wert im If-None-Match-Header. Stimmt der aktuelle ETag noch überein, antwortet der Server mit 304 Not Modified ohne Body und spart Bandbreite.
HTTP/1.1 200 OK
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Content-Type: image/jpeg
Content-Length: 89342
[Bilddaten]
# Spätere Anfrage
GET /image.jpg HTTP/1.1
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
# Antwort
HTTP/1.1 304 Not ModifiedETags können strong (Byte für Byte identisch) oder weak (semantisch gleich, Präfix W/) sein. Strong ETags sind meist ein Hash des Inhalts (SHA1, MD5, xxHash). Weak ETags helfen, wenn kleine Formatierungsunterschiede den Cache nicht entwerten sollen.
Was ist Last-Modified?
Last-Modified ist ein Zeitstempel-Validator mit Sekundengenauigkeit. Der Client sendet ihn als If-Modified-Since zurück:
HTTP/1.1 200 OK
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT
# Später
GET /article HTTP/1.1
If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT
# Antwort
HTTP/1.1 304 Not ModifiedVerglichen mit ETag ist Last-Modified einfacher, aber begrenzt: alles, was sich öfter als einmal pro Sekunde ändert, kann nicht unterschieden werden. Für datenbankgestützte Inhalte (ein WordPress-Post, der zweimal in derselben Minute aktualisiert wird) ist ETag die bessere Wahl.
Was ist der Vary-Header?
Vary teilt dem Cache mit, dass die Antwort von bestimmten Request-Headern abhängt. Der Cache muss pro Kombination eine eigene Kopie speichern. Häufige Beispiele:
Vary: Accept-Encodingtrennt gzip, brotli und unkomprimierte Kopien.Vary: Accept-Languagetrennt Sprachversionen.Vary: User-Agenttrennt Desktop- und Mobile-HTML. Vermeiden, weil jede Browserversion einen neuen Cache-Key erzeugt.Vary: Cookiedeaktiviert Shared Caching faktisch, weil jeder Benutzer einzigartige Cookies hat. Fast immer falsch.
Browser-Cache vs. CDN-Cache vs. Proxy-Cache
| Cache-Ebene | Ort | Befolgt |
|---|---|---|
| Browser-Cache | Lokale Festplatte oder RAM des Geräts | max-age, no-cache, no-store, ETag, Last-Modified |
| CDN-Edge-Cache | CDN-PoP nahe am Nutzer (Cloudflare, Fastly, Akamai, CloudFront) | s-maxage, public, stale-while-revalidate, Surrogate-Key, Cache-Tag |
| Unternehmens-Proxy | In Firmennetzwerken | public, private (heute selten relevant) |
| Service-Worker-Cache | In der Seite via JavaScript | Eigene Logik, ignoriert HTTP-Header standardmäßig |
Cache Busting und Fingerprinting
Langes max-age (ein Jahr) plus immutable ist Top für Performance, aber wie deployt man eine neue Version? Antwort: Fingerprinting. Build-Tools (webpack, Vite, esbuild, Turbopack, Rollup) fügen einen Content-Hash in den Dateinamen ein. app.css wird zu app.a1b2c3d4.css. Ändert sich die Datei, ändert sich der Hash, ändert sich die URL, Cache Miss automatisch. HTML referenziert diese fingerprintet Assets, daher sollte HTML selbst KEIN langes Caching haben. Muster:
- HTML:
Cache-Control: public, max-age=0, s-maxage=60, stale-while-revalidate=86400 - JS/CSS/Fonts/Bilder mit Hash:
Cache-Control: public, max-age=31536000, immutable
HTTP-Caching in WordPress
WordPress Core sendet von Haus aus sehr schwache Cache-Header. Best Practice ist, Header per Caching-Plugin oder am Webserver zu setzen. Optionen:
- WP Rocket: kostenpflichtig, setzt Browser-Cache-Header, liefert vorgerendertes HTML, unterstützt stale-while-revalidate.
- LiteSpeed Cache: kostenlos, integriert mit LiteSpeed und OpenLiteSpeed, ESI für Partial Caching, CDN-Hook.
- W3 Total Cache: kostenlos, ausgereift, Browser-Cache-Regeln, Object Cache (Redis, Memcached) und CDN-Integration.
- WP Super Cache: kostenlos, einfacher Full-Page-Cache von Automattic.
- Cloudflare APO (Automatic Platform Optimization): cacht HTML am Edge für 5 USD/Monat, handhabt eingeloggte WordPress-Nutzer über Cookies.
nginx-Beispielkonfiguration für WordPress:
location ~* \.(jpg|jpeg|png|gif|webp|avif|svg|ico|css|js|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location / {
try_files $uri $uri/ /index.php?$args;
add_header Cache-Control "public, max-age=0, s-maxage=600, stale-while-revalidate=86400";
}Häufige HTTP-Caching-Fehler
- Langes max-age auf HTML: Nutzer sehen nach einem Deploy alten Inhalt, Hard Reload nötig.
- Statische Assets ohne Header: jeder Seitenaufruf lädt das gleiche Logo neu.
- Vary: User-Agent: explodiert die Anzahl der Cache-Keys im CDN.
- Set-Cookie zusammen mit Cache-Control: public: Shared Caches können das Cookie speichern und an andere Nutzer ausliefern.
- Pragma: no-cache: ist ein HTTP/1.0-Request-Header, von modernen Servern und CDNs ignoriert. Cache-Control verwenden.
- Gar keine Header: Browser fallen auf heuristisches Caching zurück (10 Prozent des Last-Modified-Alters), unvorhersehbar.
- Cache Poisoning: enthält der Cache-Key nicht alle relevanten Header, kann ein Angreifer den Cache mit bösartigem Inhalt vergiften. Immer
Varyfür jeden Request-Header setzen, der die Antwort beeinflusst.
Wie teste ich HTTP-Caching?
- Browser DevTools Network Tab: (memory cache) oder (disk cache) bedeutet Hit, 304 bedeutet revalidiert. Response-Header anschauen.
- curl:
curl -I https://example.de/style.cssgibt Header aus. - WebPageTest: zeigt Cache-Scores pro Asset und bewertet die Konfiguration.
- Lighthouse: prüft "Uses efficient cache policy on static assets".
- RedBot (
redbot.org): kostenloses Tool von Mark Nottingham, das HTTP-Caching-Header analysiert und auf subtile Fehler hinweist.
Was ist mit HTTP/2 und HTTP/3?
HTTP/2 (RFC 7540, Mai 2015) und HTTP/3 (RFC 9114, Juni 2022) behalten die Caching-Semantik bei, fügen aber Server Push hinzu (seit 2022 in Chrome zugunsten von Early Hints, RFC 8297, eingestellt). Early Hints (103 Early Hints) erlauben es Servern, kritische Ressourcen vor der eigentlichen Antwort vorzuladen, was den Cache ergänzt statt ersetzt.
Wie hilft InspectWP bei HTTP-Caching?
InspectWP prüft die Response-Header der HTML-Seite und aller verknüpften Assets jeder analysierten URL. Der Report markiert fehlende Cache-Control-Header, zu kurze max-age-Werte auf fingerprinted Assets, fehlende ETag- oder Last-Modified-Validatoren und gefährliche Vary-Kombinationen.