Wenn du eine API entwickelst, möchtest du sie so effizient wie möglich machen. Jede Anfrage an den Server verbraucht Rechenleistung, Bandbreite und erhöht die Latenz. Hier kommt HTTP-Caching ins Spiel. Es ermöglicht es dem Client (z. B. einem Browser oder einem Proxy), bestimmte Antworten lokal zu speichern und bei Bedarf erneut zu verwenden, anstatt jedes Mal den Server zu kontaktieren.
Die Vorteile von Spring Boot Caching:
- Reduzierte Serverlast: Weniger Anfragen bedeuten weniger Berechnungen auf dem Server.
- Schnellere Antwortzeiten: Wenn Daten aus dem Cache geladen werden, entfällt die Wartezeit auf eine Antwort vom Server.
- Geringerer Datenverbrauch: Besonders bei mobilen Nutzern oder begrenzter Bandbreite kann Caching erhebliche Einsparungen bringen.
- Bessere Skalierbarkeit: Systeme können mehr Benutzer bedienen, da sie nicht ständig dieselben Daten neu berechnen müssen.
Aber Vorsicht: Nicht alles sollte gecacht werden! Wenn du sensible oder sich oft ändernde Daten hast (z. B. Nutzerprofile oder Banktransaktionen), willst du sicherstellen, dass der Client immer die aktuellste Version der Daten bekommt.
Hier erfährst du mehr über den Spring Boot Cache. Also lass uns direkt loslegen.

Das Problem: Spring Boot setzt automatisch Cache-Control: no-cache
Spring Boot und insbesondere Spring Security haben standardmäßig die Angewohnheit, Cache-Control: no-cache, no-store, must-revalidate
in den Headern zu setzen. Das bedeutet, dass Browser oder Proxies nichts cachen dürfen. Warum?
- Sicherheit: Bei sensiblen Informationen wie Login-Daten oder personalisierten Inhalten möchtest du nicht, dass ein alter, eventuell falscher Cache-Wert geladen wird.
- Korrektheit: Manche Daten müssen immer aktuell sein (z. B. Bestandszahlen in einem Online-Shop oder Nutzerkontostände).
Das Problem ist nur: Nicht alle API-Responses brauchen dieses Verhalten. Wenn du beispielsweise eine statische Liste von Produktkategorien oder eine JSON-Antwort mit Wetterdaten zurückgibst, sollte Caching erlaubt sein.

Cache-Control gezielt steuern
Spring Boot erlaubt es uns, den Cache-Control
-Header explizit zu setzen. Wenn du willst, dass der Client (Browser oder Proxy) deine API-Responses 1 Minute lang cacht, kannst du das mit folgender Methode steuern:
return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
.body(myProfileResponse);
Hier passiert Folgendes:
maxAge(60, TimeUnit.SECONDS)
: Die Antwort darf 60 Sekunden lang gecacht werden.- Der Browser oder ein Proxy kann also innerhalb dieser Zeitspanne die Antwort aus dem Cache laden, ohne den Server erneut zu fragen.
Möchtest du gar keinen Cache-Control-Header setzen, kannst du stattdessen CacheControl.empty()
verwenden:
return ResponseEntity.ok()
.cacheControl(CacheControl.empty())
.body(myProfileResponse);
Das sorgt dafür, dass kein Cache-Control
-Header in der Antwort enthalten ist. Doch Vorsicht: Falls Spring Security aktiv ist, setzt es trotzdem no-cache
! Das schauen wir uns als nächstes an.

Spring Boot Caching verhindern? So deaktivierst du es in Spring Security.
Falls du Spring Security nutzt, wird oft automatisch Cache-Control: no-cache
gesetzt, selbst wenn du explizit versuchst, ihn zu entfernen. Um dieses Verhalten zu überschreiben, kannst du folgendes tun:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.headers(headers -> headers.cacheControl(cache -> cache.disable()))
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
.build();
}
Hier passiert folgendes:
.cacheControl(cache -> cache.disable())
schaltet das automatische Setzen vonCache-Control: no-cache
ab.- Nun kannst du selbst entscheiden, ob du den Header setzen willst oder nicht.
Falls du weiterhin Probleme hast, dass Cache-Control
erzwungen wird, solltest du den Header manuell entfernen.

Security-Aspekte im Caching
Cache-Leaks vermeiden
Falls sensible Daten (z. B. Nutzerprofile oder Auth-Tokens) über eine API zurückgegeben werden, sollte sichergestellt werden, dass diese nicht gecacht werden:
return ResponseEntity.ok()
.cacheControl(CacheControl.noStore())
.body(sensitiveData);
Verhinderung von Cache-Poisoning
Cache-Poisoning ist eine gefährliche Angriffsmethode, bei der manipulierte Inhalte in den Cache eingeschleust werden, um diese später an Benutzer auszuliefern. In Spring Boot-Anwendungen kann dies zu erheblichen Sicherheitsproblemen führen, insbesondere wenn sensible Daten zwischengespeichert werden. In diesem Abschnitt zeige ich, wie man Cache-Poisoning effektiv verhindert.
Um zu verhindern, dass personenbezogene Daten für mehrere Benutzer gecacht werden, sollte der Cache-Control
-Header auf private
gesetzt werden. Dies stellt sicher, dass nur der ursprüngliche Client auf die gecachten Daten zugreifen kann.
return ResponseEntity.ok()
.cacheControl(CacheControl.privateCache())
.body(userProfileResponse);
Der Vary
-Header sorgt dafür, dass unterschiedliche Varianten derselben Ressource basierend auf spezifischen Headern gespeichert werden. Beispielsweise kann eine API-Antwort, die auf dem Authorization
-Header basiert, gezielt nur für authentifizierte Benutzer gecacht werden.
return ResponseEntity.ok()
.header(HttpHeaders.VARY, "Authorization")
.body(userProfileResponse);
Sichere Implementierung von ETags
Falls ETag
genutzt wird, sollte sichergestellt sein, dass keine sensiblen Informationen im ETag enthalten sind:
String eTag = DigestUtils.md5DigestAsHex(responseBody.getBytes());
return ResponseEntity.ok()
.eTag(eTag)
.body(responseBody);

Cache-Control-Header komplett entfernen
Wenn du absolut sicherstellen willst, dass Cache-Control
nicht gesendet wird, kannst du den Header auch explizit löschen:
ResponseEntity<ProfileResponse> response = ResponseEntity.ok().body(myProfileResponse);
HttpHeaders headers = new HttpHeaders();
headers.putAll(response.getHeaders());
headers.remove("Cache-Control");
return new ResponseEntity<>(myProfileResponse, headers, HttpStatus.OK);
Diese Methode sorgt dafür, dass Cache-Control
gar nicht erst in der Antwort vorkommt.
Fazit & Best Practices mit Spring Boot Caching
✅ Setze gezielt Cache-Control
-Header, um die gewünschte Cache-Dauer zu definieren.
✅ Nutze ETag
und Last-Modified
, um effizienteres Caching zu ermöglichen.
✅ Vermeide Cache-Leaks durch no-store
für sensible Daten.
✅ Schütze dich vor Cache-Poisoning mit korrekten Vary
-Headern.
✅ Nutze einen globalen Filter, falls du in der gesamten App Cache-Control
entfernen willst.
Mit diesen Techniken stellst du sicher, dass deine API-Responses optimal gecacht & sicher sind! 🚀