You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Spring Cloud Gateway实现无循环的Sidecar双向流量代理?

Great question! That infinite loop is a classic pitfall when building sidecar proxies—your current setup can't tell apart external inbound requests and the outbound requests coming from your backend app. Let's fix this properly with Spring Cloud Gateway, which is tailor-made for this sidecar scenario.

Solution Overview

We'll split the sidecar's responsibilities into two distinct routes, using a custom header to distinguish request types:

  • Inbound route: Handles external client requests, validates auth headers, then forwards to your backend app.
  • Outbound route: Handles backend app's outgoing requests, adds the required auth header, then forwards to external services.

The custom header will act as a "fingerprint" to prevent loops—backend app adds it to all its outbound requests, so the sidecar knows not to route those back to itself.


Step 1: Configure Your Backend App to Target the Sidecar

First, update your backend app to send all outbound requests to the sidecar, and add a custom header like X-Proxy-Source: backend-app to mark these requests. Here's how to do it for common HTTP clients:

For WebClient:

@Bean
public WebClient webClient() {
    return WebClient.builder()
            .baseUrl("http://localhost:8081") // Sidecar's port
            .defaultHeader("X-Proxy-Source", "backend-app")
            .build();
}

For RestTemplate:

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    
    // Add the custom header to all outgoing requests
    restTemplate.getInterceptors().add((request, body, execution) -> {
        request.getHeaders().add("X-Proxy-Source", "backend-app");
        return execution.execute(request, body);
    });
    
    // Route all requests through the sidecar proxy
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    factory.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8081)));
    restTemplate.setRequestFactory(factory);
    
    return restTemplate;
}

Step 2: Build the Sidecar with Spring Cloud Gateway

1. Add Dependencies

Ensure your sidecar's pom.xml includes these core dependencies:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
</dependencies>

2. Gateway Route Configuration (application.yml)

This config defines the two routes and uses predicates to filter request types:

server:
  port: 8081 # Sidecar's listening port

spring:
  cloud:
    gateway:
      routes:
        # Route 1: Handle external inbound requests
        - id: inbound-route
          uri: http://localhost:8080 # Your backend app's port
          predicates:
            - Path=/**
            - Header=!X-Proxy-Source # Only match requests WITHOUT the custom header
          filters:
            - name: RequestAuthValidator # Custom filter to check auth header
              args:
                requiredHeader: Authorization
            - RewritePath=/**, /$1 # Preserve original path when forwarding

        # Route 2: Handle backend app's outbound requests
        - id: outbound-route
          uri: https://default-external-service.com # Placeholder; will be overridden
          predicates:
            - Path=/**
            - Header=X-Proxy-Source, backend-app # Only match requests FROM backend
          filters:
            - name: OutboundAuthAdder # Custom filter to add auth header
              args:
                authValue: Bearer YOUR_DYNAMIC_OR_STATIC_TOKEN
            - RemoveRequestHeader=X-Proxy-Source # Clean up before sending to external services
            - RewriteLocationResponseHeader=AS_IN_REQUEST, Location, .* # Fix redirects

3. Custom Gateway Filters

Implement the two filters to handle auth validation and header addition:

a. RequestAuthValidator (Inbound Validation)

@Component
public class RequestAuthValidator implements GatewayFilter, Ordered {

    private final String requiredHeader;

    public RequestAuthValidator(@Value("${spring.cloud.gateway.routes[0].filters[0].args.requiredHeader}") String requiredHeader) {
        this.requiredHeader = requiredHeader;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // Reject requests missing the required auth header
        if (!exchange.getRequest().getHeaders().containsKey(requiredHeader)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        
        // Optional: Add logic to validate the header's value here (e.g., JWT check)
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1; // Run this filter first
    }
}

b. OutboundAuthAdder (Outbound Header Addition)

@Component
public class OutboundAuthAdder implements GatewayFilter, Ordered {

    private final String authValue;

    public OutboundAuthAdder(@Value("${spring.cloud.gateway.routes[1].filters[0].args.authValue}") String authValue) {
        this.authValue = authValue;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // Add the required auth header and remove our custom source header
        ServerHttpRequest modifiedRequest = exchange.getRequest().mutate()
                .header("Authorization", authValue)
                .headers(headers -> headers.remove("X-Proxy-Source"))
                .build();
        
        return chain.filter(exchange.mutate().request(modifiedRequest).build());
    }

    @Override
    public int getOrder() {
        return 0; // Run after route matching
    }
}

Step 3: How This Prevents Infinite Loops

The magic is in the route predicates:

  • External requests don't have the X-Proxy-Source header, so they match the inbound route and get forwarded to your backend app.
  • Backend app's outgoing requests have X-Proxy-Source: backend-app, so they match the outbound route and get sent to external services—never looping back to the backend.

Bonus: Spring Cloud Netflix Sidecar Alternative

If you want a more out-of-the-box solution, Spring Cloud's Netflix Sidecar module is built specifically for this sidecar pattern. It auto-registers your backend app as a service, handles proxying, and lets you add custom filters for auth logic. The custom Gateway approach gives you more granular control, but Sidecar can save you boilerplate code.

内容的提问来源于stack exchange,提问作者Alstresh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 11:07:28