In Microservice-Architekturen sitzt vor jedem Dienst eine eigene API, jeder Dienst hat eine eigene URL und eigene Authentifizierung – für Clients eine Zumutung. Ein API-Gateway fasst alle Dienste unter einer zentralen URL zusammen, leitet Requests weiter und übernimmt Querschnittsaufgaben wie Authentifizierung, Rate Limiting und Logging. Spring Cloud Gateway ist der reaktive, auf WebFlux basierende Gateway-Baustein des Spring-Ökosystems.
Warum ein API-Gateway?
Ohne Gateway kommuniziert jeder Client direkt mit jedem Microservice – ein Albtraum bei wachsender Dienstanzahl:
- CORS-Konfiguration pro Dienst
- Authentifizierung muss jeder Dienst einzeln implementieren
- Client muss alle Service-URLs kennen
- Kein zentrales Rate Limiting oder Load Balancing
Mit einem Gateway laufen alle Client-Requests über eine zentrale Adresse https://api.meineapp.de. Das Gateway routet dann basierend auf dem Pfad an den richtigen Backend-Dienst.
Abhängigkeit und erste Route
Spring Cloud Gateway wird als normale Spring Boot Starter-Abhängigkeit eingebunden. Ab Spring Cloud Gateway 5.x (Spring Boot 4.x) gibt es zwei Varianten: die reaktive WebFlux-Variante und eine servlet-basierte Web-MVC-Variante.
Reaktive Variante (WebFlux):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway-server-webflux</artifactId>
</dependency>
Code-Sprache: HTML, XML (xml)
Servlet-Variante (Web MVC):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway-server-webmvc</artifactId>
</dependency>
Code-Sprache: HTML, XML (xml)
Die WebFlux-Variante ist der etablierte Standard und wird in diesem Artikel verwendet. Die MVC-Variante eignet sich für Projekte, die bewusst auf das Servlet-Modell setzen und keine reaktive Programmierung benötigen.
Eine Route in application.yml:
spring:
cloud:
gateway:
routes:
- id: bestell-service
uri: http://localhost:8081
predicates:
- Path=/api/bestellungen/**
filters:
- StripPrefix=1
Code-Sprache: JavaScript (javascript)
Requests an GET /api/bestellungen/42 werden an http://localhost:8081/bestellungen/42 weitergeleitet. StripPrefix=1 entfernt das erste Pfadsegment (/api).
Route-Predicates
Predicates bestimmen, ob eine Route auf einen Request zutrifft. Die häufigsten sind:
- id: user-service
uri: http://localhost:8082
predicates:
- Path=/api/users/**
- Method=GET,POST
- Header=X-Version, v2
- Query=debug, true
- Cookie=session, .*
- Host=api.meineapp.de
Code-Sprache: JavaScript (javascript)
Nur wenn alle Predicates zutreffen, wird die Route aktiv. Beliebige Kombinationen sind möglich.
Gateway-Filter
Filter modifizieren eingehende Requests oder ausgehende Responses. Spring Cloud Gateway unterscheidet Pre-Filter (vor dem Routing) und Post-Filter (nach der Backend-Antwort).
Request-Header modifizieren
filters:
- AddRequestHeader=X-Gateway, true
- RemoveRequestHeader=Cookie
- SetRequestHeader=X-Api-Key, ${API_KEY}
Code-Sprache: JavaScript (javascript)
Rate Limiting mit Redis
- id: rate-limited-service
uri: http://localhost:8081
predicates:
- Path=/api/limit/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@ipKeyResolver}"
Code-Sprache: JavaScript (javascript)
Dazu ein KeyResolver-Bean, das den Client anhand der IP identifiziert:
@Bean
KeyResolver ipKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getRemoteAddress()
.getAddress().getHostAddress());
}
Code-Sprache: CSS (css)
10 Requests pro Sekunde (replenishRate) mit einer Burst-Toleranz von 20. Redis wird als Backend für den Token-Bucket-Algorithmus benötigt.
Circuit Breaker mit Resilience4j
filters:
- name: CircuitBreaker
args:
name: backendA
fallbackUri: forward:/fallback/backendA
Code-Sprache: JavaScript (javascript)
Wenn der Backend-Dienst nicht erreichbar ist, wird der Circuit geöffnet und eine konfigurierte Fallback-Route aktiv – ohne dass der Client eine Fehlermeldung sieht.
Dynamisches Routing mit Discovery Service
In Kombination mit einem Service-Registry (Eureka, Consul) kann das Gateway Dienste automatisch entdecken:
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
- id: dynamic-bestell
uri: lb://BESTELL-SERVICE
predicates:
- Path=/api/bestellungen/**
Code-Sprache: JavaScript (javascript)
lb:// aktiviert clientseitiges Load Balancing über mehrere Instanzen des Dienstes. Fällt eine Instanz aus, verteilt das Gateway automatisch auf die verbleibenden.
Eigenen Gateway-Filter programmieren
Neben den eingebauten Filtern lassen sich eigene Filter schreiben:
@Component
public class TimingFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
long start = System.currentTimeMillis();
return chain.filter(exchange)
.doFinally(signalType -> {
long dauer = System.currentTimeMillis() - start;
log.info("Request {} dauerte {} ms",
exchange.getRequest().getPath(), dauer);
});
}
}
Code-Sprache: PHP (php)
Globale Filter werden auf jede Route angewandt – ideal für Logging, Tracing oder benutzerdefinierte Sicherheitschecks.
Gateway-Filter in der MVC-Variante
Wer die Web-MVC-Variante nutzt, programmiert Filter nicht als GlobalFilter, sondern als HandlerFilterFunction. Die Konfiguration erfolgt über eine funktionale Router-API:
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.*;
@Bean
public RouterFunction<ServerResponse> customRoutes() {
return route("bestell-service")
.GET("/api/bestellungen/**", http())
.before(uri("http://localhost:8081"))
.before(rewritePath("/api/(?<segment>.*)", "/${segment}"))
.build();
}
Code-Sprache: JavaScript (javascript)
Die MVC-Variante verzichtet auf reaktive Typen wie Mono und Flux und nutzt stattdessen die vertraute Servlet-API. YAML-Konfiguration funktioniert in beiden Varianten identisch.
Sicherheit mit Spring Security
Das Gateway ist der natürliche Ort für Authentifizierung. Mit Spring Security und OAuth2:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth.meineapp.de
Code-Sprache: JavaScript (javascript)
Jeder eingehende Request wird auf ein gültiges JWT geprüft, bevor er überhaupt das Backend erreicht. Die Microservices dahinter können sich auf andere Aufgaben konzentrieren.
Fazit
Spring Cloud Gateway ist der zentrale Eingangspunkt für moderne Microservice-Landschaften. Es routet Requests anhand flexibler Predicates, modifiziert sie über Filter und übernimmt Querschnittsaufgaben wie Rate Limiting, Circuit Breaking und Authentifizierung zentral. Die reaktive Basis auf WebFlux garantiert hohen Durchsatz, die nahtlose Integration mit Service Discovery reduziert Konfigurationsaufwand. Seit Version 5.x steht mit der Web-MVC-Variante auch eine servlet-basierte Alternative zur Verfügung – ideal für Teams, die nicht vollständig auf reaktive Programmierung umsteigen möchten. Wer Spring Boot im Backend einsetzt, findet im Gateway den passenden Eintrittspunkt.