My project use springboot3.1.8 (spring-web 6.0.16) , and I use RestTemplate with Okhttp4.12.0 for making calls to REST endpoints , the initialize code as follows :
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
OkHttpClient client = new OkHttpClient().newBuilder().connectionPool(new ConnectionPool(300, 300, TimeUnit.SECONDS)).build();
OkHttp3ClientHttpRequestFactory httpRequestFactory = new OkHttp3ClientHttpRequestFactory(client);
restTemplate.setRequestFactory(httpRequestFactory);
return restTemplate;
}
and the call code as follows :
@Test
void testGet() {
String getUrl = "https://api.weixin.qq.com/sns/jscode2session";
String body = restTemplate.getForEntity(getUrl, String.class).getBody();
}
@Test
void testPost() {
String postUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=34534543fdgdfg4545";
Map<String, String> bodyMap = Map.of("code", "xxxxx");
String body = restTemplate.postForEntity(postUrl, bodyMap, String.class).getBody();
}
the result as follows:
testGet:{"errcode":41002,"errmsg":"appid missing, rid: 661632da-22de497f-36b92d2a"}
testPost:{"errcode":40001,"errmsg":"invalid credential"}
and when I upgrade my springboot version to 3.2.4(spring-web 6.1.5) , the same code run result as follows:
testGet:{"errcode":41002,"errmsg":"appid missing, rid: 661632da-22de497f-36b92d2a"}
testPost:
org.springframework.web.client.HttpClientErrorException: 412 Precondition Failed: [no body]
at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:136)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:183)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:137)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:942)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:891)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:790)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:538)
at com.example.demo.controller.HttpTest.testOkHttpPost(HttpTest.java:28)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
After upgrade , Get request work ok,but post request work error,and then I found the change(spring-web 6.1.X) in wiki
To reduce memory usage in RestClient and RestTemplate, most ClientHttpRequestFactory implementations no longer buffer request bodies before sending them to the server. As a result, for certain content types such as JSON, the contents size is no longer known, and a Content-Length header is no longer set. If you would like to buffer request bodies like before, simply wrap the ClientHttpRequestFactory you are using in a BufferingClientHttpRequestFactory.
so I change My initialize code as follows :
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
OkHttpClient client = new OkHttpClient().newBuilder().connectionPool(new ConnectionPool(300, 300, TimeUnit.SECONDS)).build();
BufferingClientHttpRequestFactory bufferingClientHttpRequestFactory = new BufferingClientHttpRequestFactory(new OkHttp3ClientHttpRequestFactory(client));
restTemplate.setRequestFactory(bufferingClientHttpRequestFactory);
return restTemplate;
}
and I run my code again ,the result as follows:
testGet:
java.lang.IllegalArgumentException: method GET must not have a request body.
at okhttp3.Request$Builder.method(Request.kt:258)
at org.springframework.http.client.OkHttp3ClientHttpRequest.executeInternal(OkHttp3ClientHttpRequest.java:88)
at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:70)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66)
at org.springframework.http.client.BufferingClientHttpRequestWrapper.executeInternal(BufferingClientHttpRequestWrapper.java:75)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:889)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:790)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:431)
at com.example.demo.controller.HttpTest.testOkHttpGet(HttpTest.java:37)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
testPost:{"errcode":40001,"errmsg":"invalid credential"}
I found , After change(using BufferingClientHttpRequestFactory) , post request work ok , but get request work wrong
so did I miss some configuration? or is there any other suggestions for modifications?
Comment From: bclozel
Do you see the same behavior with okhttp3? While okhttp4 is binary compatible, we don't support this version of the library officially. Also, we have deprecated this request factory entirely, see #30919.
Can you reproduce the same behavior with a public API like httpbin.org? It would be easier for us to investigate the issue if we can reproduce the problem using a sample app that you could provide.
Comment From: shengk
I haven't tested with okhttp3 or public API yet , and I can give it a try。
and I can provide another Information : the same API like I described above, I have tested with httpclient5,and Get、Post request work ok with BufferingClientHttpRequestFactory
@Bean
public RestTemplate httpComponentRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClientBuilder().build());
BufferingClientHttpRequestFactory bufferingClientHttpRequestFactory = new BufferingClientHttpRequestFactory(clientHttpRequestFactory);
restTemplate.setRequestFactory(bufferingClientHttpRequestFactory);
return restTemplate;
}
private HttpClientBuilder httpClientBuilder() {
return HttpClients.custom().setConnectionManager(poolingHttpClientConnectionManager());
}
private PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(1000);
connectionManager.setDefaultMaxPerRoute(500);
return connectionManager;
}
Comment From: shengk
I have finish test,with public API:https://httpbin.org/get ,still getting an error
@Test
void testGet() {
String getUrl = "https://httpbin.org/get";
String body = restTemplate.getForEntity(getUrl, String.class).getBody();
System.out.println(body);
}
java.lang.IllegalArgumentException: method GET must not have a request body.
at okhttp3.Request$Builder.method(Request.kt:258)
at org.springframework.http.client.OkHttp3ClientHttpRequest.executeInternal(OkHttp3ClientHttpRequest.java:88)
at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:70)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66)
at org.springframework.http.client.BufferingClientHttpRequestWrapper.executeInternal(BufferingClientHttpRequestWrapper.java:75)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:889)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:790)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:431)
at com.example.demo.test.HttpTest.testGet(HttpTest.java:37)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
and All scenes i use okHttp3.14.9,It's the same situation
Comment From: shengk
I Trace the source code,in spring-web(6.1.5) the error throws at spring's OkHttp3ClientHttpRequest ->executeInternal() ->builder.method(this.method.name(), requestBody)
and At this time,requestBody is not null,it has body and headers two nodes,and body's running type is BufferingClientHttpRequestWrapper . body has two nodes too , the first is bufferedOutput ,and it’s value is not null but an Empty array,I don't know if it's a problem here