← Kursa Dön
📄 Text · 35 min

Spring Cloud Gateway

Mikroservis mimarisinde düzinelerce servis vardır ve her birinin farklı adresi/portu bulunur. İstemcilerin (web, mobil) tüm bu adresleri bilmesi ve her servisle ayrı ayrı iletişim kurması pratik değildir. API Gateway, istemci ile mikroservisler arasında tek bir giriş noktası (single entry point) sağlar. Spring Cloud Gateway, Spring ekosisteminin resmi API Gateway çözümüdür.

API Gateway vs Reverse Proxy

İkisi benzer görünse de kapsamları farklıdır:

Reverse Proxy (Nginx, HAProxy): Temel yönlendirme, SSL termination, static file serving, basit load balancing. Uygulama mantığı yoktur.

API Gateway: Reverse proxy'nin tüm yeteneklerini içerir + authentication/authorization, request/response transformation, rate limiting, circuit breaker, logging, monitoring, API composition. İş mantığı katmanı içerir.

Spring Cloud Gateway Kurulumu

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

Önemli: Spring Cloud Gateway, Spring WebFlux (reactive) üzerine kuruludur. spring-boot-starter-web (servlet-based) ile birlikte kullanılamaz.

Route Kavramı

Gateway'in temel yapı taşı route'tur. Her route üç bileşenden oluşur:

  1. Predicate — İsteğin bu route ile eşleşip eşleşmediğini belirler.

  2. Filter — İstek veya yanıtı dönüştürür.

  3. URI — İsteğin yönlendirileceği hedef.

YAML ile Route Tanımlama

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service        # lb = load balanced
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=0

        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - StripPrefix=0

        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/api/products/**
            - Method=GET,POST
          filters:
            - AddRequestHeader=X-Gateway, true
            - AddResponseHeader=X-Response-Time, processed

lb:// prefix'i Eureka'dan servis adresini çözümlemek için Spring Cloud LoadBalancer'ı kullanır.

Java DSL ile Route Tanımlama

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r
                .path("/api/users/**")
                .filters(f -> f
                    .stripPrefix(0)
                    .addRequestHeader("X-Source", "gateway")
                    .retry(config -> config
                        .setRetries(3)
                        .setStatuses(HttpStatus.SERVICE_UNAVAILABLE)))
                .uri("lb://user-service"))

            .route("order-service", r -> r
                .path("/api/orders/**")
                .and()
                .method(HttpMethod.GET, HttpMethod.POST)
                .filters(f -> f
                    .circuitBreaker(config -> config
                        .setName("orderCB")
                        .setFallbackUri("forward:/fallback/orders")))
                .uri("lb://order-service"))
            .build();
    }
}

Route Predicates (Eşleştirme Kuralları)

Gateway zengin bir predicate seti sunar:

predicates:
  - Path=/api/users/**              # URL path eşleştirme
  - Method=GET,POST                  # HTTP metot filtresi
  - Header=X-Request-Id, \d+        # Header regex ile eşleştirme
  - Query=category                   # Query parameter varlığı
  - Query=category, electronics      # Query parameter değeri
  - After=2024-01-01T00:00:00+03:00  # Belirli tarihten sonra
  - Before=2025-12-31T23:59:59+03:00 # Belirli tarihten önce
  - Between=2024-01-01T00:00:00+03:00, 2024-12-31T23:59:59+03:00
  - Cookie=session, abc.*            # Cookie eşleştirme
  - RemoteAddr=192.168.1.0/24       # IP adresi filtresi
  - Weight=group1, 8                 # Ağırlıklı yönlendirme

Gateway Filters

Pre-filters — İstek servise ulaşmadan önce çalışır:

filters:
  - AddRequestHeader=X-Request-Source, gateway
  - RemoveRequestHeader=Cookie
  - SetPath=/internal{path}
  - StripPrefix=1           # /api/users/42 → /users/42
  - PrefixPath=/v1          # /users/42 → /v1/users/42
  - RequestSize=5000000     # max 5MB request

Post-filters — Yanıt istemciye dönmeden önce çalışır:

filters:
  - AddResponseHeader=X-Powered-By, Spring Gateway
  - RemoveResponseHeader=Server
  - SetStatus=200

Global Filter (Tüm Route'lara Uygulanan)

@Component
public class LoggingGlobalFilter implements GlobalFilter, Ordered {

    private static final Logger log =
        LoggerFactory.getLogger(LoggingGlobalFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange,
                              GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().toString();
        String method = exchange.getRequest().getMethod().name();
        long start = System.currentTimeMillis();

        log.info(">>> {} {}", method, path);

        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            long duration = System.currentTimeMillis() - start;
            int status = exchange.getResponse().getStatusCode() != null
                ? exchange.getResponse().getStatusCode().value() : 0;
            log.info("<<< {} {} → {} ({}ms)",
                method, path, status, duration);
        }));
    }

    @Override
    public int getOrder() {
        return -1; // düşük sıra = önce çalışır
    }
}

Rate Limiting ve Circuit Breaker Entegrasyonu

Gateway, route seviyesinde RequestRateLimiter filtresi ile rate limiting ve CircuitBreaker filtresi ile circuit breaker entegrasyonu sunar. Rate limiting için Redis backend, circuit breaker için Resilience4j kullanılır:

filters:
  - name: RequestRateLimiter
    args:
      redis-rate-limiter.replenishRate: 10
      redis-rate-limiter.burstCapacity: 20
      key-resolver: "#{@userKeyResolver}"
  - name: CircuitBreaker
    args:
      name: orderServiceCB
      fallbackUri: forward:/fallback/orders
@RestController
public class FallbackController {
    @GetMapping("/fallback/orders")
    public ResponseEntity<Map<String, String>> ordersFallback() {
        return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
            .body(Map.of("message", "Order service temporarily unavailable"));
    }
}

Spring Cloud Gateway, mikroservis mimarinizin ön kapısıdır. Tüm cross-cutting concern'leri merkezi olarak yönetir ve servislerinizi dış dünyadan soyutlar.