简体   繁体   English

Spring Cloud Gateway - 为每条路由设置不同的代理

[英]Spring Cloud Gateway - set Different Proxy for each route

Is their any way we can configure proxy for each route.他们是否可以通过任何方式为每条路由配置代理。

Incoming request A -> route A matched -> just forward to target system Incoming request B -> route B matched -> set proxy for target system call -> forward to target system using the proxy传入请求 A -> 路由 A 匹配 -> 仅转发到目标系统 传入请求 B -> 路由 B 匹配 -> 为目标系统调用设置代理 -> 使用代理转发到目标系统

if I use set proxy using spring cloud gateway it is getting applied to all the routes如果我使用 spring 云网关设置代理,它将被应用于所有路由

spring.cloud.gateway.httpclient.proxy.host= spring.cloud.gateway.httpclient.proxy.port= spring.cloud.gateway.httpclient.proxy.host= spring.cloud.gateway.httpclient.proxy.port=

Do you have any idea/ link/ code snippet how to solve that issue?你有任何想法/链接/代码片段如何解决这个问题吗? Any hint is welcome.欢迎任何提示。

spring:
  cloud:
    gateway:
      routes:
        - id: route1
          metadata:
            proxy-host: proxyhost
            proxy-port: 1000
          predicates:
          - Path=...
          uri: ...

        - id: route2
          metadata:
            proxy-host: proxyhost2
            proxy-port: 1000
          predicates:
          - Path=...
          uri: ...

kotlin科特林

@Component
class CustomNettyRoutingFilter(
    private val httpClient: HttpClient,
    headersFiltersProvider: ObjectProvider<List<HttpHeadersFilter>>,
    properties: HttpClientProperties,
) : NettyRoutingFilter(
    httpClient,
    headersFiltersProvider,
    properties
) {
    private val httpClientCacheMap: ConcurrentMap<String, HttpClient> = ConcurrentHashMap()

    override fun getHttpClient(route: Route, exchange: ServerWebExchange): HttpClient {
        val proxyHost = route.metadata["proxy-host"] as? String
        val proxyPort = route.metadata["proxy-port"] as? Int
        return httpClientCacheMap.getOrPut(route.id) {
            when {
                proxyHost != null && proxyPort != null -> {
                    httpClient.proxy { proxySpec ->
                        proxySpec.type(ProxyProvider.Proxy.HTTP)
                            .host(proxyHost)
                            .port(proxyPort)
                    }
                }
                else -> httpClient
            }
        }
    }
}

Is this gonna help you?这会帮助你吗?

In my service, every client has their own API server.在我的服务中,每个客户端都有自己的 API 服务器。 So different endpoints are assigned according to the clientId by the OriginMappingFilter .因此OriginMappingFilter会根据clientId分配不同的端点。

For example, After authentication,例如,认证后,
if clientId header matched client1,如果 clientId 标头与 client1 匹配,
http://gateway.com/shops/every-resource is reached to http://client1.com/shops/every-resource http://gateway.com/shops/every-resource到达http://client1.com/shops/every-resource

if clientId header matched client2,如果 clientId 标头与 client2 匹配,
http://gateway.com/shops/every-resource is reached to http://client2.com/shops/every-resource http://gateway.com/shops/every-resource到达http://client2.com/shops/every-resource

@SpringBootApplication
public class GatewayApplication {

    @Value("${token.secret}")
    String tokenSecret;
    
    @Autowired
    private AuthenticationFilter authenticationfilter;
    
    @Autowired
    private OriginMappingFilter originMappingFilter;
    
    public static void main(String[] args) {
        SpringApplication.run(AutomangatewayApplication.class, args);
    }
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        
        return builder.routes()
                .route(r -> r.path("/clients/*/tokens-with/*").uri("http://localhost:8081"))
                                    
                .route(r -> r.path("/shops/**").filters(f -> f.filter(authenticationfilter).filter(originMappingFilter)).uri("no://op"))
                
                .build();
    }
    
    @Bean
    public TokenUtils tokenUtils() {
        return new TokenUtils(tokenSecret);
    }
    
    @Bean
    public RestTemplate restTemplate() {
       return new RestTemplate();
    }
    
}
@Component
public class OriginMappingFilter implements GatewayFilter, Ordered {
    
    private static final String LEGACY_WEBSERVER_ORIGIN = "http://localhost:9095";
    
    @Autowired
    private RestTemplate restTemplate;

    @Override
    public int getOrder() {
        return 10000;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        try {

            ServerHttpRequest request = exchange.getRequest();
            
            String clientId = request.getHeaders().get("clientId").get(0);
            String origin = originOfClient(clientId);

            URI newURI = new URI(origin + request.getPath().pathWithinApplication().value());
            
            System.out.println("destination: " + newURI.toString());

            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, newURI);
            return chain.filter(exchange);
            
            
        } catch (URISyntaxException e ) {
            e.printStackTrace();
            throw new IllegalStateException("can't map client to origin",e);
        } catch (HttpServerErrorException e) {
            e.printStackTrace();
            throw new IllegalStateException("can't access to client resource",e);
        }
    }

    private String originOfClient(String clientId) {
        
        ResponseEntity<String> response =  restTemplate.getForEntity(LEGACY_WEBSERVER_ORIGIN+"/clients/"+clientId+"/ip", String.class);
        String ip = response.getBody();
        String origin = "http://"+ip+":8082";
        
        return origin;
    }
}

I could solve it like this我可以这样解决

Step 1 : Define metadata for proxy in route第 1 步:为路由中的代理定义元数据

@Configuration
public class MyRouteConfiguration {
    @Bean
    public RouteLocator routes( //
            final RouteLocatorBuilder locatorBuilder, //
            final MyRoutingConfiguration routingConfiguration) {
        RouteLocatorBuilder.Builder builder = locatorBuilder.routes();
        routingConfiguration //
                .getRoutings() //
                .stream() //
                .forEach(routing -> builder //
                        .route(p -> p //
                                .path(toPatternString(routing.getPaths())) //
                                .filters(f -> f //
                                        .rewritePath(routing.getRewriteRegex(), routing.getRewriteReplacement()) //
                                .metadata("proxy-host", routing.getProxyHost()) //
                                .metadata("proxy-port", routing.getProxyPort()) //
                                .metadata("proxy-username", routing.getProxyUsername()) //
                                .metadata("proxy-password", routing.getProxyPassword()) //
                                .uri(routing.getUri())));
    
        return builder.build();
    }

Step 2 : Create a component extending from NettyRoutingFilter第 2 步:创建一个从NettyRoutingFilter扩展的组件

@Component
public class HttpClientFilter extends NettyRoutingFilter {
    public HttpClientFilter(HttpClient httpClient, ObjectProvider<List<HttpHeadersFilter>> headersFiltersProvider,
            HttpClientProperties properties) {
        super(httpClient, headersFiltersProvider, properties);
    }
    @Override
    protected HttpClient getHttpClient(Route route, ServerWebExchange exchange) {
        Map<String, Object> metadata = route.getMetadata();
        String proxyHost = (String) metadata.getOrDefault("proxy-host", "default-host");
        String proxyPort = (String) metadata.getOrDefault("proxy-port", "default-port");
        String username = (String) metadata.getOrDefault("proxy-username", "default-user");
        String pass = (String) metadata.getOrDefault("proxy-password", "default-password");
        return super.getHttpClient(route, exchange) .proxy(proxy -> proxy //
                .type(ProxyProvider.Proxy.HTTP) //
                .host(proxyHost) //
                .port(Integer.valueOf(proxyPort)) //
                .username(username) //
                .password(password -> password = pass));
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM