Affects: spring 6.1.0-RC2 with spring boot 3.2.0-RC2 and JDK21
Description
I've attached a sample Spring Boot application with a single endpoint that accepts PATCH requests. When the endpoint is invoked with a PATCH request from a WebTestClient
it is allowed, but when it is invoked with a PATCH request from a RestClient
, it fails with the following exception
org.springframework.web.client.ResourceAccessException: I/O error on PATCH request for "http://localhost:61668/api/endpoint": Invalid HTTP method: PATCH
at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.createResourceAccessException(DefaultRestClient.java:489)
at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeInternal(DefaultRestClient.java:414)
at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.retrieve(DefaultRestClient.java:380)
In SecurityConfiguration.java
I've added PATCH to the allowed methods, so I guess RestClient
is ignoring this configuration.
Steps to Reproduce demo.zip
The application contains 2 integration tests, one of which invokes the endpoint with a RestClient
and the other uses WebTestClient
. The latter test passes, but the former fails.
Comment From: poutsma
Spring Boot's RestClient
support uses the SimpleClientHttpRequestFactory
by default, which is based on the dated java.net.HttpURLConnection
, and does not have support for PATCH
.
Switching to the more modern Java HttpClient fixes it:
@PostConstruct
private void buildRestClient() {
restClient = restClientBuilder.baseUrl("http://localhost:" + port)
.requestFactory(new JdkClientHttpRequestFactory())
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
Comment From: andrei-ivanov
Wouldn't it make sense to change the default client?
Comment From: donalmurtagh
Spring Boot's
RestClient
support uses theSimpleClientHttpRequestFactory
by default, which is based on the datedjava.net.HttpURLConnection
, and does not have support forPATCH
.Switching to the more modern Java HttpClient fixes it:
@poutsma Thanks very much for your reply, I've confirmed that switching the request factory resolves the problem.
Given that RestClient
is brand new, shouldn't it use JdkClientHttpRequestFactory
by default i.e. there doesn't appear to be a backwards compatibility argument for using HttpURLConnection
Comment From: poutsma
Wouldn't it make sense to change the default client?
FWIW, RestClient
's default request factory—without Boot—is the JdkClientHttpRequestFactory
.
It is because Boot uses the same ClientHttpRequestFactorySettings
between RestTemplate
and RestClient
that the SimpleClientHttpRequestFactory
is used, doing otherwise would break backward compatibility for RestTemplate
users because the factories have different behavior with regards to redirects.
There are plans to improve the situation, see https://github.com/spring-projects/spring-boot/issues/36266