HTTP Caching Strategien
HTTP Caching: Strategien für schnelle Websites
Richtiges Caching reduziert Ladezeiten und Serverkosten drastisch. Lernen Sie die HTTP-Caching-Mechanismen und ihre optimale Konfiguration.
Caching-Header im Überblick
| Header | Funktion |
|---|---|
| Cache-Control | Hauptsteuerung (modern) |
| ETag | Validierung (Fingerprint) |
| Last-Modified | Validierung (Datum) |
| Expires | Ablaufdatum (veraltet) |
| Vary | Cache-Varianten |
Cache-Control Direktiven
# Öffentlich cachebar (CDNs, Proxies) Cache-Control: public, max-age=31536000 # Nur Browser-Cache Cache-Control: private, max-age=3600 # Kein Caching Cache-Control: no-store # Cachen, aber immer validieren Cache-Control: no-cache # Wichtige Direktiven: max-age=SEKUNDEN # Wie lange frisch s-maxage=SEKUNDEN # Für Shared Caches (CDN) no-cache # Validieren vor Nutzung no-store # Nie speichern private # Nur Browser, kein CDN public # Überall cachebar must-revalidate # Nach Ablauf validieren immutable # Ändert sich nie stale-while-revalidate=SEKUNDEN # Stale Content während Revalidation
Caching-Strategien nach Dateityp
# Statische Assets mit Hash (immutable) # bundle.a1b2c3d4.js Cache-Control: public, max-age=31536000, immutable # Bilder Cache-Control: public, max-age=86400 # HTML (immer frisch prüfen) Cache-Control: no-cache # API-Responses (variiert) Cache-Control: private, max-age=0, must-revalidate # Fonts Cache-Control: public, max-age=31536000, immutable # CSS/JS ohne Hash Cache-Control: public, max-age=604800, stale-while-revalidate=86400
Nginx Konfiguration
# /etc/nginx/conf.d/caching.conf
# Statische Assets (1 Jahr)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary "Accept-Encoding";
}
# HTML (immer validieren)
location ~* \.html$ {
add_header Cache-Control "no-cache";
etag on;
}
# API (kein Cache)
location /api/ {
add_header Cache-Control "no-store";
}
# Mit Versioning im Dateinamen
location ~* \.[a-f0-9]{8,}\.(js|css)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
Apache Konfiguration
# .htaccess
<IfModule mod_expires.c>
ExpiresActive On
# Standard
ExpiresDefault "access plus 1 month"
# HTML
ExpiresByType text/html "access plus 0 seconds"
# CSS/JS
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
# Bilder
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
# Fonts
ExpiresByType font/woff2 "access plus 1 year"
</IfModule>
<IfModule mod_headers.c>
# Immutable für versionierte Assets
<FilesMatch "\.[a-f0-9]{8,}\.(js|css)$">
Header set Cache-Control "public, immutable"
</FilesMatch>
</IfModule>
ETag und Validierung
# Server sendet ETag HTTP/1.1 200 OK ETag: "abc123" Cache-Control: no-cache # Browser fragt später: GET /resource HTTP/1.1 If-None-Match: "abc123" # Wenn unverändert: HTTP/1.1 304 Not Modified # → Keine Datenübertragung, Browser nutzt Cache # Wenn verändert: HTTP/1.1 200 OK ETag: "def456" # → Neue Daten
# Last-Modified Alternative HTTP/1.1 200 OK Last-Modified: Tue, 15 Jan 2024 10:00:00 GMT # Browser fragt: GET /resource HTTP/1.1 If-Modified-Since: Tue, 15 Jan 2024 10:00:00 GMT # 304 wenn unverändert, 200 wenn neu
Vary Header
# Verschiedene Cache-Versionen basierend auf: # Encoding (gzip vs brotli) Vary: Accept-Encoding # Sprache Vary: Accept-Language # Mehrere Faktoren Vary: Accept-Encoding, Accept-Language # Nie cachen (für jeden Request anders) Vary: * # Beispiel: Responsive Images Vary: Accept, DPR, Width
CDN-spezifische Header
# Cloudflare Cache-Control: public, s-maxage=86400, max-age=3600 # CDN cached 1 Tag, Browser 1 Stunde # Stale Content während Origin-Fehler Cache-Control: public, max-age=3600, stale-if-error=86400 # CDN Cache umgehen (für Tests) Cache-Control: no-cache # Oder Cloudflare-spezifisch: # Purge über API/Dashboard # Surrogate-Key für gezieltes Purgen (Fastly, etc.) Surrogate-Key: product-123 category-shoes
Cache-Busting Strategien
# 1. Filename Hashing (empfohlen)
bundle.a1b2c3d4.js
styles.e5f6g7h8.css
# Webpack
output: {
filename: '[name].[contenthash].js'
}
# Vite (automatisch)
# 2. Query String (weniger empfohlen)
script.js?v=1.2.3
# Manche Proxies cachen Query Strings nicht
# 3. Versionierte Ordner
/v1.2.3/bundle.js
Service Worker Caching
// Cache-First Strategy
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((cached) => {
return cached || fetch(event.request);
})
);
});
// Network-First mit Cache Fallback
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request)
.catch(() => caches.match(event.request))
);
});
// Stale-While-Revalidate
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.open('dynamic').then((cache) => {
return cache.match(event.request).then((cached) => {
const fetched = fetch(event.request).then((response) => {
cache.put(event.request, response.clone());
return response;
});
return cached || fetched;
});
})
);
});
Debugging
# Response Header prüfen curl -I https://example.com/style.css # Mit allen Details curl -v https://example.com/style.css 2>&1 | grep -E '< (Cache|ETag|Last|Expires|Vary)' # Browser DevTools # Network Tab → Headers → Response Headers # Spalte "Size": "(from disk cache)" oder "(from memory cache)" # Chrome: chrome://net-internals/#httpCache
💡 Goldene Regel:
Assets mit Content-Hash im Dateinamen:
max-age=31536000, immutable. HTML und API-Responses: no-cache mit ETag. Testen Sie Ihre Caching-Strategie mit dem Enjyn Domain Toolkit.