Reputation: 36984
I have following code:
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
FileSystemResource fileSystemResource = new FileSystemResource(fileNameWithPath);
map.add("file", fileSystemResource);
map.add("type", fileType);
map.add("org_id", systemSettingsService.getSystemSettings().getOrganizationId());
map.add("stone_id", stoneId);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);
restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class)
If I provide all parameters correct - enpoint returns 200 http stsatus code as expected as a Postman application.
But if I provide wrong url - I see exception:
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://external_server/api/v1/push_file1": Broken pipe (Write failed); nested exception is java.net.SocketException: Broken pipe (Write failed)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:666)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
at com.pack.GenericDataServiceImpl.pushAttachment(GenericDataServiceImpl.java:311)
at com.pack.FailedAttachmentPushReSender.retryFailedPushes(FailedAttachmentPushReSender.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call$$$capture(Executors.java:511)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java)
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
at java.util.concurrent.FutureTask.run(FutureTask.java)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748) Caused by: java.net.SocketException: Broken pipe (Write failed)
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
at sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:431)
at sun.security.ssl.OutputRecord.write(OutputRecord.java:417)
at sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:886)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:857)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
at org.apache.http.impl.io.SessionOutputBufferImpl.streamWrite(SessionOutputBufferImpl.java:124)
at org.apache.http.impl.io.SessionOutputBufferImpl.write(SessionOutputBufferImpl.java:160)
at org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:113)
at org.apache.http.entity.ByteArrayEntity.writeTo(ByteArrayEntity.java:114)
at org.apache.http.impl.DefaultBHttpClientConnection.sendRequestEntity(DefaultBHttpClientConnection.java:156)
at org.apache.http.impl.conn.CPoolProxy.sendRequestEntity(CPoolProxy.java:160)
at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:238)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:89)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:652) ... 20 more
But when I modify url in postman at the same manner - I see 404 error:
I want to have response like in postman and response as in postman.
In case if I provide File
instead of FileSystemResource
I get the correct HttpStatusException
where I can extract data I want:
catch (HttpStatusCodeException e) {
String response = e.getResponseBodyAsString();
logger.error("Error during attachment push for file: {}, responseText: {}", fileNameWithPath, response, e);
}
How can I write universal code which will extract response
and httpStatusCode
?
RestTemplate initialization:
CloseableHttpClient httpClient
= HttpClients.custom()
.setSSLHostnameVerifier(new NoopHostnameVerifier())
.build();
HttpComponentsClientHttpRequestFactory requestFactory
= new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
restTemplate = new RestTemplate(requestFactory);
I've read RestTemplate ClientHttpResponse.getBody() throws I/O Error but looks like already use suggested factory
I tried this:
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(buildAttachmentPushUrl());
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addBinaryBody("file", fileSystemResource.getFile(), ContentType.APPLICATION_OCTET_STREAM, fileSystemResource.getFilename());
builder.addTextBody("type", fileType);
builder.addTextBody("org_id", systemSettingsService.getSystemSettings().getOrganizationId());
builder.addTextBody("stone_id", stoneId);
HttpEntity multipart = builder.build();
httpPost.setEntity(multipart);
CloseableHttpResponse response = client.execute(httpPost);
logger.info("response code {}", response.getStatusLine().getStatusCode());
client.close();
} catch (IOException e) {
e.printStackTrace();
}
But result the same - socket write error
Upvotes: 2
Views: 3442
Reputation: 38777
How can I get real http code and response body using restTemplate?
The short answer is you cannot, because there isn't one.
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://external_server.ventures/api/v1/push_file1": Software caused connection abort: socket write error; nested exception is java.net.SocketException: Software caused connection abort: socket write error
Read the exception message. The cause (for which you have omitted the stacktrace) is a java.net.SocketException
with an underlying socket write error
.
You never received a response because you probably never finished sending a request. See the linked question for some reasons why.
RestClientResponseException
is what you want to catch. It covers all errors related to responses that you may receive, and provides access to the status, headers and body. What you've got being thrown is ResourceAccessException
, which covers all the I/O errors that can happen and don't have any response.
Upvotes: 2
Reputation: 2168
I normally use this pattern, may be it works for you
try{
ResponseEntity<String> responseEntity = restTemplate.exchange(url, httpMethod, httpEntity, String.class);
HttpStatus.Series responseSeries = responseEntity.getStatusCode().series();
if(!HttpStatus.Series.SERVER_ERROR.equals(responseSeries)){
return responseEntity;
}
}
catch(HttpClientErrorException e){
//handle exception here
//Response received from server: {} ", e.getResponseBodyAsString());
}
catch (RestClientException e) {
//handle exception here
}
catch (Exception e) {
//handle exception here
}
Upvotes: 0