Spring Cloud Gateway - Quick Reference
Deep Knowledge: Use
mcp__documentation__fetch_docswith technology:spring-cloud-gatewayfor comprehensive documentation.
Dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- For service discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Basic Configuration
application.yml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- AddRequestHeader=X-Gateway, true
- id: order-service
uri: lb://ORDER-SERVICE
predicates:
- Path=/api/orders/**
- Method=GET,POST,PUT,DELETE
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: orderCB
fallbackUri: forward:/fallback/orders
discovery:
locator:
enabled: true
lower-case-service-id: true
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Origin
- AddResponseHeader=X-Response-Time, ${now}
Route Predicates
Path Predicate
predicates:
- Path=/api/users/**
- Path=/api/v{version}/users/** # Path variable
Header Predicate
predicates:
- Header=X-Request-Id, \d+
- Header=Authorization, Bearer.*
Method Predicate
predicates:
- Method=GET,POST
Query Predicate
predicates:
- Query=page
- Query=status, active|pending
Host Predicate
predicates:
- Host=**.myhost.org
Time Predicates
predicates:
- After=2024-01-01T00:00:00+00:00
- Before=2025-12-31T23:59:59+00:00
- Between=2024-01-01T00:00:00+00:00, 2025-12-31T23:59:59+00:00
Built-in Filters
Request Modification
filters:
- AddRequestHeader=X-Request-Foo, Bar
- AddRequestParameter=foo, bar
- RemoveRequestHeader=Cookie
- SetPath=/api/v2/{segment}
- RewritePath=/api/(?<segment>.*), /$\{segment}
- StripPrefix=2
- PrefixPath=/api
Response Modification
filters:
- AddResponseHeader=X-Response-Foo, Bar
- RemoveResponseHeader=X-Internal-Header
- RewriteResponseHeader=X-Request-Id, , -
- SetStatus=401
Rate Limiting
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
redis-rate-limiter.requestedTokens: 1
key-resolver: "#{@userKeyResolver}"
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getHeaders()
.getFirst("X-User-Id"));
}
Circuit Breaker
filters:
- name: CircuitBreaker
args:
name: myCircuitBreaker
fallbackUri: forward:/fallback
statusCodes:
- 500
- 503
Retry
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
methods: GET
backoff:
firstBackoff: 100ms
maxBackoff: 500ms
factor: 2
Java Configuration
RouteLocator Bean
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user-service", r -> r
.path("/api/users/**")
.filters(f -> f
.stripPrefix(1)
.addRequestHeader("X-Gateway", "true")
.circuitBreaker(c -> c
.setName("userCB")
.setFallbackUri("forward:/fallback/users")))
.uri("lb://USER-SERVICE"))
.route("order-service", r -> r
.path("/api/orders/**")
.and()
.method(HttpMethod.GET, HttpMethod.POST)
.filters(f -> f
.stripPrefix(1)
.retry(retryConfig -> retryConfig
.setRetries(3)
.setStatuses(HttpStatus.BAD_GATEWAY)))
.uri("lb://ORDER-SERVICE"))
.build();
}
}
Custom Filters
Global Filter
@Component
@Order(-1)
public class LoggingGlobalFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
long startTime = System.currentTimeMillis();
String requestId = UUID.randomUUID().toString();
exchange.getRequest().mutate()
.header("X-Request-Id", requestId);
log.info("Request {} {} started - ID: {}",
exchange.getRequest().getMethod(),
exchange.getRequest().getURI().getPath(),
requestId);
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
long duration = System.currentTimeMillis() - startTime;
log.info("Request {} completed in {}ms - Status: {}",
requestId, duration,
exchange.getResponse().getStatusCode());
}));
}
}
Custom GatewayFilter
@Component
public class AuthenticationFilter implements GatewayFilterFactory<AuthenticationFilter.Config> {
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String token = exchange.getRequest().getHeaders()
.getFirst(HttpHeaders.AUTHORIZATION);
if (token == null || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// Validate token
try {
Claims claims = validateToken(token.substring(7));
exchange.getRequest().mutate()
.header("X-User-Id", claims.getSubject())
.header("X-User-Roles", claims.get("roles", String.class));
} catch (Exception e) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
};
}
@Override
public Class<Config> getConfigClass() {
return Config.class;
}
public static class Config {
// Configuration properties
}
}
Fallback Controller
@RestController
@RequestMapping("/fallback")
public class FallbackController {
@GetMapping("/users")
public Mono<ResponseEntity<Map<String, String>>> usersFallback() {
return Mono.just(ResponseEntity
.status(HttpStatus.SERVICE_UNAVAILABLE)
.body(Map.of(
"error", "User service is currently unavailable",
"message", "Please try again later"
)));
}
@GetMapping("/orders")
public Mono<ResponseEntity<Map<String, String>>> ordersFallback() {
return Mono.just(ResponseEntity
.status(HttpStatus.SERVICE_UNAVAILABLE)
.body(Map.of(
"error", "Order service is currently unavailable",
"message", "Please try again later"
)));
}
}
CORS Configuration
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://myapp.com"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
Actuator Endpoints
management:
endpoints:
web:
exposure:
include: gateway,health,info
endpoint:
gateway:
enabled: true
# List all routes
GET /actuator/gateway/routes
# Get specific route
GET /actuator/gateway/routes/{id}
# Refresh routes
POST /actuator/gateway/refresh
# Get global filters
GET /actuator/gateway/globalfilters
# Get route filters
GET /actuator/gateway/routefilters
Best Practices
| Do | Don't | |----|-------| | Use service discovery (lb://) | Hardcode service URLs | | Implement circuit breakers | Let failures cascade | | Add request/response logging | Deploy without observability | | Configure rate limiting | Allow unlimited requests | | Use path-based routing | Over-complicate predicates |
Production Checklist
- [ ] Service discovery enabled
- [ ] Circuit breakers configured
- [ ] Rate limiting implemented
- [ ] CORS properly configured
- [ ] Authentication filter added
- [ ] Logging/tracing enabled
- [ ] Fallback handlers defined
- [ ] Actuator endpoints secured
- [ ] Timeouts configured
- [ ] Health checks enabled
When NOT to Use This Skill
- Simple proxy - Use nginx for basic routing
- Zuul - Deprecated, migrate to Gateway
- Non-reactive - Gateway is WebFlux-based
- Edge functions - Consider Cloudflare Workers, Lambda@Edge
Anti-Patterns
| Anti-Pattern | Problem | Solution | |--------------|---------|----------| | Blocking calls in filters | Degrades performance | Use reactive operators | | No rate limiting | DDoS vulnerability | Add RequestRateLimiter | | Missing circuit breaker | Cascading failures | Integrate with Resilience4j | | No timeouts | Hanging requests | Configure response timeout | | Logging body | Memory issues | Log only metadata |
Quick Troubleshooting
| Problem | Diagnostic | Fix | |---------|------------|-----| | Route not matching | Check predicates | Verify path, method, headers | | Service unavailable | Check discovery | Verify lb:// service name | | Filters not executing | Check order | Verify filter chain order | | CORS issues | Check CORS config | Add GlobalCorsProperties | | Timeouts | Check response-timeout | Increase or fix downstream |
Scan to join WeChat group