Zum Hauptinhalt springen

[Medium] 📄 HTTP Caching

1. What is HTTP caching and why is it important?​

Was ist HTTP-Caching? Warum ist es wichtig?

HTTP-Caching ist eine Technik, bei der HTTP-Antworten vorĂŒbergehend auf dem Client (Browser) oder auf Zwischenservern gespeichert werden, damit bei nachfolgenden Anfragen die gecachten Daten direkt verwendet werden können, ohne den Server erneut anzufragen.

Cache vs. temporĂ€re Speicherung: Was ist der Unterschied?​

In technischen Dokumentationen werden diese beiden Begriffe oft synonym verwendet, haben aber tatsÀchlich unterschiedliche Bedeutungen:

Cache​

Definition: Datenkopien, die zur Leistungsoptimierung gespeichert werden, mit Schwerpunkt auf „Wiederverwendung" und „schnellerem Zugriff".

Merkmale:

  • ✅ Ziel ist die Leistungssteigerung
  • ✅ Daten können wiederholt verwendet werden
  • ✅ Klare Ablaufrichtlinien vorhanden
  • ✅ In der Regel Kopien der Originaldaten

Beispiel:

// HTTP Cache - API-Antworten cachen
Cache-Control: max-age=3600 // 1 Stunde cachen

// Memory Cache - Berechnungsergebnisse cachen
const cache = new Map();
function fibonacci(n) {
if (cache.has(n)) return cache.get(n); // Cache wiederverwenden
const result = /* Berechnung */;
cache.set(n, result);
return result;
}

Temporary Storage (TemporĂ€re Speicherung)​

Definition: VorĂŒbergehend gespeicherte Daten, mit Schwerpunkt auf „TemporalitĂ€t" und „werden gelöscht".

Merkmale:

  • ✅ Ziel ist die vorĂŒbergehende Speicherung
  • ✅ Wird nicht unbedingt wiederverwendet
  • ✅ Lebenszyklus ist in der Regel kurz
  • ✅ Kann ZwischenzustĂ€nde enthalten

Beispiel:

// sessionStorage - Benutzereingaben temporÀr speichern
sessionStorage.setItem('formData', JSON.stringify(form)); // Wird beim Schließen des Tabs gelöscht

// Datei-Upload temporÀr speichern
const tempFile = await uploadToTemp(file); // Nach Verarbeitung löschen
await processFile(tempFile);
await deleteTempFile(tempFile);

Vergleichstabelle​

EigenschaftCacheTemporary Storage (TemporÀre Speicherung)
HauptzweckLeistungsoptimierungVorĂŒbergehende Speicherung
WiederverwendungJa, mehrfaches LesenNicht unbedingt
LebenszyklusRichtlinienbasiertIn der Regel kurz
Typische VerwendungHTTP Cache, Memory CachesessionStorage, temporÀre Dateien
Englische EntsprechungCacheTemp / Temporary / Buffer

Unterschiede in der praktischen Anwendung​

// ===== Cache-Szenarien =====

// 1. HTTP Cache: API-Antworten wiederverwenden
fetch('/api/users') // Erste Anfrage
.then((response) => response.json());

fetch('/api/users') // Zweite Anfrage aus dem Cache
.then((response) => response.json());

// 2. Berechnungsergebnisse cachen
const memoize = (fn) => {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key); // Wiederverwenden
const result = fn(...args);
cache.set(key, result);
return result;
};
};

// ===== Temporary Storage-Szenarien =====

// 1. Formulardaten temporĂ€r speichern (versehentliches Schließen verhindern)
window.addEventListener('beforeunload', () => {
sessionStorage.setItem('formDraft', JSON.stringify(formData));
});

// 2. Upload-Dateien temporÀr speichern
async function handleUpload(file) {
const tempPath = await uploadToTempStorage(file); // TemporÀr speichern
const processed = await processFile(tempPath);
await deleteTempFile(tempPath); // Nach Verwendung löschen
return processed;
}

// 3. Zwischenergebnisse temporÀr speichern
const tempResults = []; // Zwischenergebnisse temporÀr speichern
for (const item of items) {
tempResults.push(process(item));
}
const final = combine(tempResults); // Nach Verwendung nicht mehr benötigt

Anwendung in der Webentwicklung​

// HTTP Cache - Langzeitspeicherung, Wiederverwendung
Cache-Control: public, max-age=31536000, immutable
// → Browser cached diese Datei ein Jahr lang und verwendet sie wieder

// sessionStorage (temporĂ€re Speicherung) - VorĂŒbergehende Speicherung, beim Schließen gelöscht
sessionStorage.setItem('tempData', data);
// → Nur im aktuellen Tab gĂŒltig, wird beim Schließen gelöscht

// localStorage (Langzeitspeicherung) - Zwischen beiden
localStorage.setItem('userPreferences', prefs);
// → Dauerhafte Speicherung, aber nicht zur Leistungsoptimierung

Warum ist die Unterscheidung dieser beiden Konzepte wichtig?​

  1. Designentscheidungen:

    • Leistungsoptimierung nötig? → Cache verwenden
    • VorĂŒbergehende Speicherung nötig? → TemporĂ€re Speicherung verwenden
  2. Ressourcenmanagement:

    • Cache: Fokus auf Trefferquote und Ablaufrichtlinien
    • TemporĂ€re Speicherung: Fokus auf Bereinigungszeitpunkt und KapazitĂ€tsgrenzen
  3. Antworten im VorstellungsgesprÀch:

    • „Wie optimiert man die Leistung" → Cache-Strategien besprechen
    • „Wie behandelt man temporĂ€re Daten" → TemporĂ€re Speicherlösungen besprechen

In diesem Artikel besprechen wir hauptsÀchlich Cache, insbesondere den HTTP-Caching-Mechanismus.

Vorteile von Caching​

  1. Reduzierung von Netzwerkanfragen: Direkt aus dem lokalen Cache lesen, keine HTTP-Anfragen senden
  2. Verringerung der Serverlast: Weniger Anfragen, die der Server verarbeiten muss
  3. Schnellere Seitenladezeiten: Lokaler Cache-Zugriff ist viel schneller als Netzwerkanfragen
  4. Bandbreiteneinsparung: Reduzierte DatenĂŒbertragung
  5. Verbesserte Benutzererfahrung: Schnellere Seitenreaktionen, flĂŒssigere Nutzung

Cache-Typen​

┌─────────────────────────────────────┐
│ Browser-Cache-Hierarchie │
├──────────────────────────────────────
│ 1. Memory Cache (Speicher-Cache) │
│ - Am schnellsten, geringe │
│ KapazitĂ€t │
│ - Wird beim Schließen des │
│ Tabs gelöscht │
├──────────────────────────────────────
│ 2. Disk Cache (Festplatten-Cache) │
│ - Langsamer, große KapazitĂ€t │
│ - Dauerhafte Speicherung │
├──────────────────────────────────────
│ 3. Service Worker Cache │
│ - Volle Kontrolle durch │
│ Entwickler │
│ - UnterstĂŒtzung fĂŒr Offline- │
│ Anwendungen │
└─────────────────────────────────────┘

2. What are the HTTP caching strategies?​

Welche HTTP-Caching-Strategien gibt es?

Klassifizierung der Cache-Strategien​

HTTP-Caching-Strategien
├── Starker Cache (Strong Cache)
│ ├── Cache-Control
│ └── Expires
└── Verhandlungs-Cache (Negotiation Cache)
├── Last-Modified / If-Modified-Since
└── ETag / If-None-Match

1. Starker Cache (Strong Cache / Fresh)​

Merkmal: Der Browser liest direkt aus dem lokalen Cache, ohne eine Anfrage an den Server zu senden.

Cache-Control (HTTP/1.1)​

Cache-Control: max-age=3600

HĂ€ufig verwendete Direktiven:

// 1. max-age: Cache-GĂŒltigkeitsdauer (Sekunden)
Cache-Control: max-age=3600 // 1 Stunde cachen

// 2. no-cache: Servervalidierung erforderlich (Verhandlungs-Cache verwenden)
Cache-Control: no-cache

// 3. no-store: Überhaupt nicht cachen
Cache-Control: no-store

// 4. public: Kann von jedem Cache gespeichert werden (Browser, CDN)
Cache-Control: public, max-age=31536000

// 5. private: Nur vom Browser cachbar
Cache-Control: private, max-age=3600

// 6. immutable: Ressource Àndert sich nie (mit Hash-Dateiname)
Cache-Control: public, max-age=31536000, immutable

// 7. must-revalidate: Nach Ablauf muss beim Server validiert werden
Cache-Control: max-age=3600, must-revalidate

Expires (HTTP/1.0, veraltet)​

Expires: Wed, 21 Oct 2025 07:28:00 GMT

Probleme:

  • Verwendet absolute Zeit, abhĂ€ngig von der Client-Zeit
  • Ungenaue Client-Zeit fĂŒhrt zu fehlerhaftem Cache-Verhalten
  • Wurde durch Cache-Control ersetzt

2. Verhandlungs-Cache (Negotiation Cache / Validation)​

Merkmal: Der Browser sendet eine Anfrage an den Server, um zu prĂŒfen, ob die Ressource aktualisiert wurde.

Last-Modified / If-Modified-Since​

# Serverantwort (erste Anfrage)
Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT

# Browseranfrage (nachfolgende Anfrage)
If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT

Ablauf:

  1. Erste Anfrage: Server sendet Last-Modified
  2. Nachfolgende Anfrage: Browser sendet If-Modified-Since
  3. Ressource nicht geÀndert: Server antwortet mit 304 Not Modified
  4. Ressource geÀndert: Server antwortet mit 200 OK und neuer Ressource

ETag / If-None-Match​

# Serverantwort (erste Anfrage)
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

# Browseranfrage (nachfolgende Anfrage)
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

Vorteile:

  • Genauer als Last-Modified
  • Nicht zeitabhĂ€ngig, verwendet Inhalts-Hash
  • Kann Änderungen unterhalb der Sekundenebene erkennen

Last-Modified vs ETag​

EigenschaftLast-ModifiedETag
GenauigkeitSekundenebeneInhalts-Hash, genauer
LeistungSchnellerHash-Berechnung nötig, langsamer
AnwendungsfallAllgemeine statische RessourcenRessourcen mit prÀziser Kontrolle
PrioritÀtNiedrigHoch (ETag hat Vorrang)

3. How does browser caching work?​

Wie funktioniert Browser-Caching?

VollstĂ€ndiger Cache-Ablauf​

┌──────────────────────────────────────────────┐
│ Browser-Ressourcenanfrage-Ablauf │
└──────────────────────────────────────────────┘
↓
1. Memory Cache prĂŒfen
↓
┌───────┮────────┐
│ Cache gefunden? │
└───────┬────────┘
Yes │ No
↓
2. Disk Cache prĂŒfen
↓
┌───────┮────────┐
│ Cache gefunden? │
└───────┬────────┘
Yes │ No
↓
3. Service Worker prĂŒfen
↓
┌───────┮────────┐
│ Cache gefunden? │
└───────┬────────┘
Yes │ No
↓
4. Cache-Ablauf prĂŒfen
↓
┌───────┮────────┐
│ Abgelaufen? │
└───────┬────────┘
Yes │ No
↓
5. Verhandlungs-Cache validieren
↓
┌───────┮────────┐
│ Ressource │
│ geĂ€ndert? │
└───────┬────────┘
Yes │ No (304)
↓
6. Neue Ressource vom Server anfragen
↓
┌───────┮────────┐
│ Neue Ressource │
│ zurĂŒckgeben │
│ (200 OK) │
└────────────────┘

Praktisches Beispiel​

// Erste Anfrage
GET /api/data.json
Response:
200 OK
Cache-Control: max-age=3600
ETag: "abc123"

{ data: "..." }

// ========== Erneute Anfrage innerhalb 1 Stunde ==========
// Starker Cache: Direkt lokal lesen, keine Anfrage senden
// Status: 200 OK (from disk cache)

// ========== Erneute Anfrage nach 1 Stunde ==========
// Verhandlungs-Cache: Validierungsanfrage senden
GET /api/data.json
If-None-Match: "abc123"

// Ressource nicht geÀndert
Response:
304 Not Modified
(Kein Body, lokalen Cache verwenden)

// Ressource geÀndert
Response:
200 OK
ETag: "def456"

{ data: "new data" }

4. What are the common caching strategies?​

Welche gÀngigen Cache-Strategien gibt es?

1. Permanente Cache-Strategie (fĂŒr statische Ressourcen)​

// HTML: Nicht cachen, jedes Mal prĂŒfen
Cache-Control: no-cache

// CSS/JS (mit Hash): Permanent cachen
Cache-Control: public, max-age=31536000, immutable
// Dateiname: main.abc123.js

Prinzip:

  • HTML wird nicht gecacht, damit Benutzer die neueste Version erhalten
  • CSS/JS verwenden Hash-Dateinamen, bei InhaltsĂ€nderung Ă€ndert sich der Dateiname
  • Alte Versionen werden nicht verwendet, neue Versionen werden neu heruntergeladen

2. Strategie fĂŒr hĂ€ufig aktualisierte Ressourcen​

// API-Daten: Kurzzeit-Cache + Verhandlungs-Cache
Cache-Control: max-age=60, must-revalidate
ETag: "abc123"

3. Strategie fĂŒr Bildressourcen​

// Benutzer-Avatar: Mittelfristiger Cache
Cache-Control: public, max-age=86400 // 1 Tag

// Logo, Icons: Langfristiger Cache
Cache-Control: public, max-age=2592000 // 30 Tage

// Dynamische Bilder: Verhandlungs-Cache
Cache-Control: no-cache
ETag: "image-hash"

4. Cache-Empfehlungen nach Ressourcentyp​

const cachingStrategies = {
// HTML-Dateien
html: 'Cache-Control: no-cache',

// Statische Ressourcen mit Hash
staticWithHash: 'Cache-Control: public, max-age=31536000, immutable',

// Selten aktualisierte statische Ressourcen
staticAssets: 'Cache-Control: public, max-age=2592000',

// API-Daten
apiData: 'Cache-Control: private, max-age=60',

// Benutzerspezifische Daten
userData: 'Cache-Control: private, no-cache',

// Sensible Daten
sensitive: 'Cache-Control: no-store',
};

5. Service Worker caching​

Service Worker Caching

Service Worker bieten die flexibelste Cache-Kontrolle, bei der Entwickler die Cache-Logik vollstÀndig kontrollieren können.

Grundlegende Verwendung​

// Service Worker registrieren
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
// sw.js - Service Worker-Datei
const CACHE_NAME = 'my-app-v1';
const urlsToCache = [
'/',
'/styles/main.css',
'/scripts/main.js',
'/images/logo.png',
];

// Install-Event: Statische Ressourcen cachen
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(urlsToCache);
})
);
});

// Anfrage abfangen: Cache-Strategie verwenden
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
// Cache-First-Strategie
return response || fetch(event.request);
})
);
});

// Activate-Event: Alten Cache bereinigen
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
});

GĂ€ngige Cache-Strategien​

1. Cache First (Cache zuerst)​

// Geeignet fĂŒr: Statische Ressourcen
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});

2. Network First (Netzwerk zuerst)​

// Geeignet fĂŒr: API-Anfragen
self.addEventListener('fetch', (event) => {
event.respondWith(
fetch(event.request)
.then((response) => {
// Cache aktualisieren
const responseClone = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseClone);
});
return response;
})
.catch(() => {
// Netzwerk fehlgeschlagen, Cache verwenden
return caches.match(event.request);
})
);
});

3. Stale While Revalidate (Veraltet wĂ€hrend der Revalidierung)​

// Geeignet fĂŒr: Ressourcen, die schnelle Antworten brauchen, aber aktuell bleiben sollen
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
const fetchPromise = fetch(event.request).then((networkResponse) => {
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, networkResponse.clone());
});
return networkResponse;
});

// Cache zurĂŒckgeben, im Hintergrund aktualisieren
return cachedResponse || fetchPromise;
})
);
});

6. How to implement cache busting?​

Wie implementiert man Cache Busting?

Cache Busting ist eine Technik, die sicherstellt, dass Benutzer die neuesten Ressourcen erhalten.

Methode 1: Dateiname mit Hash (empfohlen)​

// Bundling-Tools wie Webpack/Vite verwenden
// Ausgabe: main.abc123.js

// webpack.config.js
module.exports = {
output: {
filename: '[name].[contenthash].js',
},
};
<!-- Referenz automatisch aktualisieren -->
<script src="/js/main.abc123.js"></script>

Vorteile:

  • ✅ Dateiname Ă€ndert sich, erzwingt den Download der neuen Datei
  • ✅ Alte Version bleibt im Cache, keine Verschwendung
  • ✅ Best Practice

Methode 2: Query String Versionsnummer​

<!-- Versionsnummer manuell aktualisieren -->
<script src="/js/main.js?v=1.2.3"></script>
<link rel="stylesheet" href="/css/style.css?v=1.2.3" />

Nachteile:

  • ❌ Einige CDNs cachen keine Ressourcen mit Query String
  • ❌ Manuelle Versionsverwaltung erforderlich

Methode 3: Zeitstempel​

// FĂŒr die Entwicklungsumgebung
const timestamp = Date.now();
const script = document.createElement('script');
script.src = `/js/main.js?t=${timestamp}`;
document.body.appendChild(script);

Verwendung:

  • Cache in der Entwicklungsumgebung vermeiden
  • Nicht fĂŒr die Produktionsumgebung geeignet (jedes Mal eine neue Anfrage)

7. Common caching interview questions​

HĂ€ufige Caching-Interviewfragen

Frage 1: Wie verhindert man, dass HTML gecacht wird?​

Klicken Sie, um die Antwort anzuzeigen
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0

Oder mit Meta-Tags:

<meta
http-equiv="Cache-Control"
content="no-cache, no-store, must-revalidate"
/>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />

Frage 2: Warum sollte man ETag verwenden und nicht nur Last-Modified?​

Klicken Sie, um die Antwort anzuzeigen

Vorteile von ETag:

  1. Genauer: Kann Änderungen unterhalb der Sekundenebene erkennen
  2. Inhaltsgesteuert: Basiert auf Inhalts-Hash, nicht auf Zeit
  3. Zeitprobleme vermeiden:
    • Dateiinhalt hat sich nicht geĂ€ndert, aber die Zeit schon (z.B. bei Re-Deployment)
    • Zyklisch aktualisierte Ressourcen (kehren periodisch zum gleichen Inhalt zurĂŒck)
  4. Verteilte Systeme: Zeiten verschiedener Server sind möglicherweise nicht synchron

Beispiel:

// Dateiinhalt hat sich nicht geÀndert, aber Last-Modified schon
// 2024-01-01 12:00 - Version A deployen (Inhalt: abc)
// 2024-01-02 12:00 - Version A erneut deployen (Inhalt: abc)
// Last-Modified hat sich geÀndert, aber der Inhalt ist gleich!

// ETag hat dieses Problem nicht
ETag: 'hash-of-abc'; // Immer gleich

Frage 3: Was ist der Unterschied zwischen from disk cache und from memory cache?​

Klicken Sie, um die Antwort anzuzeigen
EigenschaftMemory CacheDisk Cache
SpeicherortArbeitsspeicher (RAM)Festplatte
GeschwindigkeitExtrem schnellLangsamer
KapazitĂ€tKlein (MB-Bereich)Groß (GB-Bereich)
PersistenzBeim Tab-Schließen gelöschtDauerhafte Speicherung
PrioritÀtHoch (bevorzugt)Niedrig

Ladereihenfolge:

1. Memory Cache (am schnellsten)
2. Service Worker Cache
3. Disk Cache
4. HTTP Cache
5. Netzwerkanfrage (am langsamsten)

Auslösebedingungen:

  • Memory Cache: KĂŒrzlich aufgerufene Ressourcen (z.B. Seite neu laden)
  • Disk Cache: Ressourcen, die vor lĂ€ngerer Zeit aufgerufen wurden, oder große Dateien

Frage 4: Wie erzwingt man das Neuladen von Ressourcen im Browser?​

Klicken Sie, um die Antwort anzuzeigen

Entwicklungsphase:

// 1. Hard Reload (Ctrl/Cmd + Shift + R)
// 2. Cache leeren und neu laden

// 3. Zeitstempel im Code hinzufĂŒgen
const script = document.createElement('script');
script.src = `/js/main.js?t=${Date.now()}`;

Produktionsumgebung:

// 1. Dateiname mit Hash verwenden (Best Practice)
main.abc123.js // Von Webpack/Vite automatisch generiert

// 2. Versionsnummer aktualisieren
<script src="/js/main.js?v=2.0.0"></script>

// 3. Cache-Control setzen
Cache-Control: no-cache // Validierung erzwingen
Cache-Control: no-store // Überhaupt nicht cachen

Frage 5: Wie implementiert man PWA Offline-Caching?​

Klicken Sie, um die Antwort anzuzeigen
// sw.js - Service Worker
const CACHE_NAME = 'pwa-v1';
const OFFLINE_URL = '/offline.html';

// Bei Installation Offline-Seite cachen
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll([
OFFLINE_URL,
'/styles/offline.css',
'/images/offline-icon.png',
]);
})
);
});

// Anfrage abfangen
self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(() => {
// Netzwerk fehlgeschlagen, Offline-Seite anzeigen
return caches.match(OFFLINE_URL);
})
);
}
});

VollstÀndige PWA Cache-Strategie:

// 1. Statische Ressourcen cachen
caches.addAll(['/css/', '/js/', '/images/']);

// 2. API-Anfragen: Network First
// 3. Bilder: Cache First
// 4. HTML: Network First, bei Fehler Offline-Seite anzeigen

8. Best practices​

Best Practices

✅ Empfohlene Vorgehensweisen​

// 1. HTML - Nicht cachen, sicherstellen, dass Benutzer die neueste Version erhalten
// Response Headers:
Cache-Control: no-cache

// 2. CSS/JS (mit Hash) - Permanent cachen
// Dateiname: main.abc123.js
Cache-Control: public, max-age=31536000, immutable

// 3. Bilder - Langfristig cachen
Cache-Control: public, max-age=2592000 // 30 Tage

// 4. API-Daten - Kurzfristiger Cache + Verhandlungs-Cache
Cache-Control: private, max-age=60
ETag: "api-response-hash"

// 5. Service Worker fĂŒr Offline-UnterstĂŒtzung implementieren

❌ Zu vermeidende Vorgehensweisen​

// ❌ Schlecht: HTML mit langfristigem Cache
Cache-Control: max-age=31536000 // Benutzer sehen möglicherweise alte Version

// ❌ Schlecht: Expires statt Cache-Control verwenden
Expires: Wed, 21 Oct 2025 07:28:00 GMT // HTTP/1.0, veraltet

// ❌ Schlecht: Überhaupt keinen Cache setzen
// Ohne Cache-Header ist das Browserverhalten unbestimmt

// ❌ Schlecht: Gleiche Strategie fĂŒr alle Ressourcen
Cache-Control: max-age=3600 // Sollte je nach Ressourcentyp angepasst werden

Cache-Strategie-Entscheidungsbaum​

Statische Ressource?
├─ Ja → Dateiname hat Hash?
│ ├─ Ja → Permanenter Cache (max-age=31536000, immutable)
│ └─ Nein → Mittel- bis langfristiger Cache (max-age=2592000)
└─ Nein → Ist es HTML?
├─ Ja → Nicht cachen (no-cache)
└─ Nein → Ist es eine API?
├─ Ja → Kurzfristiger Cache + Verhandlung (max-age=60, ETag)
└─ Nein → Je nach AktualisierungshĂ€ufigkeit entscheiden

Reference​