In spring-web 6.0.15, this code works as expected, in spring 6.1.2 (propably because of this commit - https://github.com/spring-projects/spring-framework/commit/033bebf8cd4a2933788e1ea3540404aefdac2cf7 ) it doesn't work.
Any suggestions? is it bug in spring-web, or in my code? It seems @Deprecated
annotations have been added in 6.1 together with removal of some code without maintaining the backward compatibility in 6.1... But I am not sure if I just havent missed some release notes :(
Wierd thing is, it only happens for some requests, most of requests pass correctly, I suspect there are 2 possible reasons: 1. failed request json has length 597 bytes, passed requests has only up to 355 bytes (request content length header field) 2. new implementation is looking into Content-Length request header (old did not) and since body length is different (due to modifySomeJsonValues()), it fails with the exception
exception is low level IOException:
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://127.0.0.1:8765/bff/services/target-service/orders/": insufficient data written
at org.springframework.web.client.RestTemplate.createResourceAccessException(RestTemplate.java:905) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:885) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:821) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:682) ~[spring-web-6.1.2.jar:6.1.2]
at org.example.MyService.processRequest(MyService.java:143) ~[classes/:na]
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:859) ~[undertow-core-2.3.10.Final.jar:2.3.10.Final]
Caused by: java.io.IOException: insufficient data written
at java.base/sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.close(HttpURLConnection.java:3848) ~[na:na]
at org.springframework.http.client.SimpleClientHttpRequest.executeInternal(SimpleClientHttpRequest.java:84) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:70) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.http.client.BufferingClientHttpRequestWrapper.executeInternal(BufferingClientHttpRequestWrapper.java:75) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:879) ~[spring-web-6.1.2.jar:6.1.2]
... 121 common frames omitted
/* from controller input
HttpMethod method;
URI uri;
@RequestBody(required = false) String body;
HttpServletRequest request;
HttpServletResponse response;
*/
final HttpHeaders headers = new HttpHeaders();
final Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
headers.set(headerName, request.getHeader(headerName));
}
HttpEntity<byte[]> httpEntity = new HttpEntity<>(modifySomeJsonValues(body.getBytes(StandardCharsets.UTF_8)), headers);
ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory());
RestTemplate restTemplate = new RestTemplate(factory);
try {
ResponseEntity<byte[]> serverResponse = restTemplate.exchange(uri, method, httpEntity, byte[].class);
.......
} catch (...) {...}
Comment From: snicoll
I believe there is a note for that in the upgrade guide:
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.
Can you give that a try and report back if that doesn't help? If that's the case, we'd need you to move that code in text into a small sample we can run ourselves. You can attach a zip to this issue or push the code to a GitHub repository.
Comment From: tomaskodaj
thanks, problem solved by the hint - sorry for overlooking the release notes.
problem was original request had "content-length" and after modifyingit in modifySomeJsonValues()
it has changed... and since spring stopped using buffers and recalculating content-length, it contained wrong value... I have just removed original content-length from request and everything works again :)