My logic calls two consecutive POST requests from RestTemplate in SpringBoot. The first call always succeeds but the second call always fails with:
I/O error on POST request for "https://httpbin.org/post": httpbin.org:443 failed to respond
Everything works fine, if I either
- disable keep-alive by setting
Connection=close - put a sleep between the request calls
- remove the proxy
I've tested with spring-boot 3.3.5 and apache-httpclient 5.4.1 but the same issue occurs with spring-boot 2.7.8 and apache-httpclient 4.5.14
I'm using jdk17 and burp as proxy.
Finally I've stripped down the code only using httpclient.
public class RestTemplateDemo {
private static Logger logger = Logger.getLogger(RestTemplateDemo.class.getName());
public static void main(String[] args) {
System.setProperty("javax.net.debug", "all");
HttpHost proxy = new HttpHost("localhost", 8888);
CloseableHttpClient client = HttpClients.custom()
.setProxy(proxy)
.build();
logger.info("1. call");
callPost(client);
logger.info("2. call");
callPost(client);
}
static void callPost(CloseableHttpClient client) {
String url = "https://httpbin.org/post";
HttpPost post = new HttpPost(url);
post.setEntity(new StringEntity("test", Charset.defaultCharset()));
try (CloseableHttpResponse response = client.execute(post)) {
logger.info(response.getCode() + " " + response.getReasonPhrase());
} catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
}
}
Here's the log and stack trace:
...
INFO: 2. call
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.657 CET|SSLSocketOutputRecord.java:334|WRITE: TLSv1.3 application_data, length = 222
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.657 CET|SSLCipher.java:2066|Plaintext before ENCRYPTION (
...
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.657 CET|SSLSocketOutputRecord.java:349|Raw write (
...
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.657 CET|SSLSocketInputRecord.java:494|Raw read (
...
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.657 CET|SSLSocketInputRecord.java:214|READ: TLSv1.2 application_data, length = 35
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.657 CET|SSLSocketInputRecord.java:494|Raw read (
...
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.657 CET|SSLSocketInputRecord.java:247|READ: TLSv1.2 application_data, length = 35
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.657 CET|SSLCipher.java:1961|Plaintext after DECRYPTION (
...
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.658 CET|Alert.java:238|Received alert message (
"Alert": {
"level" : "warning",
"description": "user_canceled"
}
)
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.658 CET|SSLSocketInputRecord.java:494|Raw read (
...
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.658 CET|SSLSocketInputRecord.java:214|READ: TLSv1.2 application_data, length = 35
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.658 CET|SSLSocketInputRecord.java:494|Raw read (
...
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.658 CET|SSLSocketInputRecord.java:247|READ: TLSv1.2 application_data, length = 35
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.658 CET|SSLCipher.java:1961|Plaintext after DECRYPTION (
...
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.658 CET|Alert.java:238|Received alert message (
"Alert": {
"level" : "warning",
"description": "close_notify"
}
)
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.658 CET|SSLSocketOutputRecord.java:71|WRITE: TLSv1.3 alert(close_notify), length = 2
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.658 CET|SSLCipher.java:2066|Plaintext before ENCRYPTION (
..
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.658 CET|SSLSocketOutputRecord.java:85|Raw write (
...
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.659 CET|SSLSocketImpl.java:577|duplex close of SSLSocket
javax.net.ssl|DEBUG|10|main|2024-11-20 14:09:17.659 CET|SSLSocketImpl.java:1785|close the SSL connection (passive)
Nov 20, 2024 2:09:17 PM demo.RestTemplateDemo callPost
SEVERE: httpbin.org:443 failed to respond
org.apache.hc.core5.http.NoHttpResponseException: httpbin.org:443 failed to respond
at org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:333)
at org.apache.hc.core5.http.impl.io.HttpRequestExecutor.execute(HttpRequestExecutor.java:193)
at org.apache.hc.client5.http.impl.classic.InternalExecRuntime.lambda$execute$0(InternalExecRuntime.java:236)
at org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager$InternalConnectionEndpoint.execute(PoolingHttpClientConnectionManager.java:791)
at org.apache.hc.client5.http.impl.classic.InternalExecRuntime.execute(InternalExecRuntime.java:233)
at org.apache.hc.client5.http.impl.classic.MainClientExec.execute(MainClientExec.java:121)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.ConnectExec.execute(ConnectExec.java:199)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.ProtocolExec.execute(ProtocolExec.java:192)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.ContentCompressionExec.execute(ContentCompressionExec.java:150)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.HttpRequestRetryExec.execute(HttpRequestRetryExec.java:113)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.RedirectExec.execute(RedirectExec.java:110)
at org.apache.hc.client5.http.impl.classic.ExecChainElement.execute(ExecChainElement.java:51)
at org.apache.hc.client5.http.impl.classic.InternalHttpClient.doExecute(InternalHttpClient.java:174)
at org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:123)
at demo.RestTemplateDemo.callPost(RestTemplateDemo.java:36)
at demo.RestTemplateDemo.main(RestTemplateDemo.java:29)
Process finished with exit code 0
https://github.com/publeorg/spring-boot-rest-demo/tree/main
PS I know, that RestTemplate is deprected, but my problem occurs with legacy code. This is only a stripped down reproducable sample. In real live I also call two POST requests at different endpoints.
docker mitmproxyproxy and did not get the error. are you usingburpin your real applications?. it seems to be something with proxy causing this behavior for you. Let me know if you want to provide the steps I did.