Spring Cloud Gateway — это API Gateway поверх Project Reactor. Маршрутизация запросов, балансировка нагрузки, rate limiting, аутентификация.
Реактивный, non-blocking, легко расширяемый через фильтры.
1️⃣ Добавляем зависимости
Добавьте spring-cloud-starter-gateway — это вытащит Reactor Netty как сервер. Важно: НЕ добавляйте spring-boot-starter-web, они несовместимы. Gateway работает на WebFlux стеке.
Для service discovery добавьте spring-cloud-starter-netflix-eureka-client или spring-cloud-starter-consul-discovery.
2️⃣ Настраиваем маршруты через application.yml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
lb:// — это magic prefix для балансировки через service discovery. StripPrefix=1 срезает /api перед проксированием запроса вниз.
3️⃣ Пишем кастомный GlobalFilter
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest()
.getHeaders()
.getFirst(HttpHeaders.AUTHORIZATION);
if (token == null || !isValid(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() { return -1; } // выполняется первым
}
getOrder() с отрицательным значением — фильтр выполнится до встроенных. Возвращайте chain.filter(exchange) чтобы пропустить запрос дальше.
4️⃣ Rate Limiting через Redis
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
);
}
replenishRate — токенов в секунду, burstCapacity — максимальный burst. Требует spring-boot-starter-data-redis-reactive.
5️⃣ Circuit Breaker с Resilience4j
filters:
- name: CircuitBreaker
args:
name: userServiceCB
fallbackUri: forward:/fallback/users
@RestController
public class FallbackController {
@GetMapping("/fallback/users")
public Mono<String> usersFallback() {
return Mono.just("Users service unavailable");
}
}
Circuit Breaker открывается при превышении порога ошибок и перенаправляет на fallback endpoint вместо каскадного падения.
6️⃣ Настраиваем CORS централизованно
@Bean
public CorsWebFilter corsWebFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*");
config.addAllowedMethod("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
Настраивайте CORS на уровне Gateway — не нужно дублировать это в каждом микросервисе.
✔️ Что происходит под капотом
Запрос приходит → RoutePredicateHandlerMapping матчит маршрут по predicates → цепочка GatewayFilter обрабатывает запрос → NettyRoutingFilter проксирует вниз → цепочка фильтров обрабатывает ответ в обратном порядке.
Всё это non-blocking на Project Reactor. Один поток может обрабатывать тысячи одновременных соединений.
💡 Бонус-совет
Actuator endpoint /actuator/gateway/routes покажет все зарегистрированные маршруты в runtime — удобно для дебага. Добавьте management.endpoint.gateway.enabled=true в конфиг и можно динамически обновлять маршруты через /actuator/gateway/refresh без перезапуска.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise