spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

Gateway MVC: Service discovery with http prefix only works if RestClient.Builder is declared as a bean (which breaks lb:// routings)

Open ah1508 opened this issue 1 year ago • 2 comments

using http:// instead of lb:// for the uri property of routes definition only works if a RestClient.Builder is declared as bean:

@LoadBalanced
@Bean
RestClient.Builder restClientBuilder() {
    return RestClient.builder();
}

RestClient.Builder bean is also required for this code:

@Bean
RouterFunction<ServerResponse> getRoute() {
    return route().GET("/foo/**", http("http://foo-api"));
}

But with a RestClient.Builder bean, lb:// prefix in yml routing configuration does not work (error 500).

If http:// is the way to go @Bean @LoadBalanced RestClient.Builder could be provided by auto configuration (or documented as mandatory) and this page https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-mvc/filters/loadbalancer.html#_using_the_loadbalancer_filter_in_configuration should not mention lb:// prefix

Maybe I am wrong but it looks like "RouterFunction with http("...") only works if a @LoadBalancer @Bean RestClient.Builder exists and then lb: prefix should not be used". I don't know if it is a bug or if it should be documented but it is not obvious.

With the webflux version a @LoadBalanced WebClient.Builder bean does not break lb:// routings.

ah1508 avatar Dec 08 '23 03:12 ah1508

More informations:

Actually a RestClient.Builder is already provided by RestClientAutoConfiguration.

But adding a custom @LoadBalanced one breaks

@Bean
RouterFunction<ServerResponse> fooRouting() {
    return route()
        .GET("/foo/**", http())
	.filter(lb("foo-api"))
	.build();
}

Exception thrown by BlockingLoadBalancerClient.java:98: java.lang.IllegalArgumentException: Service Instance cannot be null.

A custom @LoadBalanced RestClient.Builder follows the documentation and is useful to write custom code in the API Gateway, for agregation purpose for instance. But is there any reason to not do that:

@Bean
RestClient restClient(LoadBalancerInterceptor loadBalancerInterceptor) {
    return RestClient.builder().requestInterceptor(loadBalancerInterceptor).build();
}

ah1508 avatar Dec 09 '23 15:12 ah1508

Any RestClient bean used by Gateway MVC should NOT be @LoadBalanced as there is a separate lb() filter for that.

This should probably be mentioned in the documentation.

spencergibb avatar Dec 20 '23 00:12 spencergibb