spring-cloud-gateway

v2026.09.24

Spring Cloud Gateway for API routing, filtering, and load balancing. Covers route predicates, filters, rate limiting, and circuit breaker integration. USE WHEN: user mentions "spring cloud gateway", "API gateway", "route predicates", "gateway filters", "rate limiting gateway", "load balancing gateway" DO NOT USE FOR: simple reverse proxy - use nginx, Zuul (deprecated) - use Spring Cloud Gateway instead

GitHub
安装命令
npx skhub add claude-dev-suite/spring-cloud-gateway
Markdown
SKILL.md

Spring Cloud Gateway - Quick Reference

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: spring-cloud-gateway for 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

DoDon't
Use service discovery (lb://)Hardcode service URLs
Implement circuit breakersLet failures cascade
Add request/response loggingDeploy without observability
Configure rate limitingAllow unlimited requests
Use path-based routingOver-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-PatternProblemSolution
Blocking calls in filtersDegrades performanceUse reactive operators
No rate limitingDDoS vulnerabilityAdd RequestRateLimiter
Missing circuit breakerCascading failuresIntegrate with Resilience4j
No timeoutsHanging requestsConfigure response timeout
Logging bodyMemory issuesLog only metadata

Quick Troubleshooting

ProblemDiagnosticFix
Route not matchingCheck predicatesVerify path, method, headers
Service unavailableCheck discoveryVerify lb:// service name
Filters not executingCheck orderVerify filter chain order
CORS issuesCheck CORS configAdd GlobalCorsProperties
TimeoutsCheck response-timeoutIncrease or fix downstream

Reference Documentation

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

2026年9月24日

分类

未分类

许可证

MIT

源路径

skills/backend-frameworks/spring-cloud-gateway

默认分支

main

最新提交

9496306

Tree SHA

fe4e2f1