Imagine the following code which creates a custom RestClient
instance, specifically using a custom requestFactory
, no beans:
val restClient = RestClient
.builder()
.requestFactory(ClientHttpRequestFactoryBuilder.httpComponents().build())
.baseUrl(config.baseUrl)
.defaultHeader(USER_AGENT_HEADER_NAME, USER_AGENT_HEADER_VALUE)
.defaultUriVariables(mapOf(CLIENT_ID_PARAMETER_NAME to config.clientId))
.requestInterceptor(BasicAuthenticationInterceptor(config.clientId, config.clientSecret))
.apply(restClientSsl.fromBundle(REST_CLIENT_SSL_BUNDLE_NAME))
.build()
When this RestClient
is created - I would expect it to use a custom request factory based on standard ClientHttpRequestFactoryBuilder.httpComponents().build()
, no Spring Beans involved.
However, instead, this RestClient
instance still uses globally defined Spring Bean, for example:
@Bean
fun httpComponentsClientHttpRequestFactoryBuilder(): HttpComponentsClientHttpRequestFactoryBuilder {
return ClientHttpRequestFactoryBuilder.httpComponents().withDefaultRequestConfigCustomizer() {
it.setProtocolUpgradeEnabled(false)
}
}
It means that I can't create a custom instance of RestClient
that ignores global configuration and instead I have to globally override the Spring Bean instance of HttpComponentsClientHttpRequestFactoryBuilder
Am I doing something wrong? :) I'm not that good with Spring however, so thanks for pointing out to the right Spring configuration, etc. There is some info here but I'm not sure.
Using Spring Boot org.springframework.boot
version 3.4.2, spring-web 6.2.2.
Thanks! π
Comment From: bclozel
Hello @user1bh The build call you have shared should work as you have described. Now you are using Spring Boot, and it's not clear how your custom client is contributed to the application context with other beans and how the auto-configuration is working in your case.
Can you share a minimal sample Spring Boot application that reproduces the behavior you are seeing please?
Comment From: user1bh
@bclozel thanks for your response! While I was creating a minimal repro-project, I have found the reason for the problem: it was the auto-configured RestClientSsl
that I used.. You've had a right guess about auto-configuration.
So now, instead of using RestClientSsl
I'm manually applying an sslBundle
however via RestTemplate
.
Instead of the following:
val restClient = RestClient
.builder()
.requestFactory(ClientHttpRequestFactoryBuilder.httpComponents().build())
.baseUrl(config.baseUrl)
.defaultHeader(USER_AGENT_HEADER_NAME, USER_AGENT_HEADER_VALUE)
.defaultUriVariables(mapOf(CLIENT_ID_PARAMETER_NAME to config.clientId))
.requestInterceptor(BasicAuthenticationInterceptor(config.clientId, config.clientSecret))
.apply(restClientSsl.fromBundle(REST_CLIENT_SSL_BUNDLE_NAME)) // The problem was here <---
.build()
Now I'm doing custom RestClient
creation via RestTemplate
:
val restClient = RestClient.create(
restTemplateBuilder
.requestFactoryBuilder(ClientHttpRequestFactoryBuilder.httpComponents())
.rootUri(config.baseUrl)
.defaultHeader(USER_AGENT_HEADER_NAME, USER_AGENT_HEADER_VALUE)
.interceptors(BasicAuthenticationInterceptor(config.clientId, config.clientSecret))
.sslBundle(sslBundles.getBundle(REST_CLIENT_SSL_BUNDLE_NAME)) // This is the fix <---
.build()
)
Maybe last question: @bclozel do you know if it's possible to supply an sslBundle
to RestClient
builder directly, without using an intermediate RestTemplate
?
Thanks! π
Comment From: bclozel
Thanks for getting back to us.
I believe this is covered in the Spring Boot reference documentation about RestClientSsl
. ClientHttpRequestFactorySettings
seems like a good approach here.
Comment From: user1bh
@bclozel thanks again! Indeed the provided example with ClientHttpRequestFactorySettings
works well π