springspring-boothttpinterfaceapache-httpcomponents

Spring Boot 3.4.0 Broken HTTP interface


I was using the latest version Spring Boot 3.3.6 with HTTP interface like following:

    @Bean
    public RestRepositoryUser restRepositoryUser(
            @NonNull @Value("${api.url}") String apiUrl) throws URISyntaxException {

        RestClient restClient = RestClient.builder().baseUrl(new URI(apiUrl)).build();

        HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder()
                .exchangeAdapter(RestClientAdapter.create(restClient)).build();

        return factory.createClient(RestRepositoryGsUser.class);
    }

with the following content on RestRepositoryUser.class

public interface RestRepositoryUser {

    @GetExchange("/api/clientPf-data")
    public ResponseEntity<List<ClientPf>> findAllPortfolios(
            @RequestHeader("api-version") String version,
            @RequestHeader("api-requesterId") String requesterId,
            @RequestHeader("api-invocationContext") String invocationContext);
}

and in my service code I use it like this

@Log4j2
@Service
@RequiredArgsConstructor
public class ServicePortfolio {

    private final RestRepositoryUser restRepositoryPortfolio;

    public List<ClientPf> findAllPortfolios() {

        ResponseEntity<List<ClientPf>> response =
                restRepositoryPortfolio.findAllPortfolios("1.0", "maydaylocal", "maydaylocal");
        log.info("FindAllPortfolios: response from api " + response.getStatusCode());
        return response.getBody();
    }
}

When I migrate on Spring boot 3.4.0, I updated accordingly the dependency for my http stuff

        <dependency>
            <groupId>org.apache.httpcomponents.client5</groupId>
            <artifactId>httpclient5</artifactId>
        </dependency>

By testing, it looks all my GET requests are not working anymore, I face a strange behavior where:

I tested to play with the new parameters "spring.http.client.factory". Per default, as I understood it is using the "http-components" one.

Adding to this new parameter, I also tried to modify my RestClient in order to use RestTemplate instead and here is what I found:

Tests with RestTemplate

Tests with RestClient:


Solution

  • Ok, found the solution. Here is what I found:

    I was calling an http endpoint on my HTTP interface. So I was thinking that this code (provided in the Spring patchnote) was useless in my case:

    public HttpComponentsClientHttpRequestFactoryBuilder httpComponentsClientHttpRequestFactoryBuilder() {
        return ClientHttpRequestFactoryBuilder.httpComponents().withDefaultRequestConfigCustomizer(
                (builder) -> builder.setProtocolUpgradeEnabled(false));
    }
    

    So, it was not the case: I have to declare it whatever if it is HTTP or HTTPS endpoint. (not sure if it is normal). I was not seeing the 401 on server side because the request was blocked by the gateway before. That being said, I still don't get why I had some timeouts, but it looks to be solved too.

    And also, I've to force the new function in my bean config:

            RestClient restClient = RestClient.builder().baseUrl(apiUrl)
                .requestFactory(httpComponentsClientHttpRequestFactoryBuilder().build()) // this line
                .defaultHeaders(header -> {
                    header.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
                    header.set("api-requesterId", "test");
                    header.set("api-invocationContext", "test");
                }).build();
    

    More info: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes#apache-http-components-and-envoy

    Those headers were causing issues:

    I hope it could help some people in my case!