Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RestTemplate ClientHttpResponse.getBody() throws I/O Error

I'm using Spring RestTemplate to make RESTful calls. I'm also using a custom ClientHttpRequestInterceptor to log the request and response for debugging purposes.

In order to read the response multiple times (once for the logging, once for processing) I use a BufferingClientHttpRequestFactory. Here's the setup:

ClientHttpRequestInterceptor ri = new LoggingRequestInterceptor();
List<ClientHttpRequestInterceptor> ris = new ArrayList<ClientHttpRequestInterceptor>();
ris.add(ri);
restTemplate.setInterceptors(ris);
restTemplate.setRequestFactory(new InterceptingClientHttpRequestFactory(
        new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()) , ris));

I'm testing this system right now against a request that returns a 422 response and am having problems. From within the intercept method of my custom ClientHttpRequestInterceptor:

ClientHttpResponse response = execution.execute(request, body);
if(response.getBody() != null) {
    logger.trace(IOUtils.toString(response.getBody(), "UTF-8"));
}

The response.getBody() throws an exception:

org.springframework.web.client.ResourceAccessException: I/O error: Server returned HTTP response code: 422 for URL: https://testurl.com/admin/orders/564/fulfill.json; nested exception is java.io.IOException: Server returned HTTP response code: 422 for URL: https://testurl.com/admin/orders/564/fulfill.json at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:461) ~[spring-web-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:409) ~[spring-web-3.1.2.RELEASE.jar:3.1.2.RELEASE]

Not sure why this happens, but I turned on the debugger and I set up a watch expression for request.getBody(). The call to request.getBody() being made in that context before it gets to my actual code fixes the error.

like image 909
IcedDante Avatar asked May 20 '15 17:05

IcedDante


People also ask

How to handle error in Rest Template?

Default Error Handling By default, the RestTemplate will throw one of these exceptions in the case of an HTTP error: HttpClientErrorException – in the case of HTTP status 4xx. HttpServerErrorException – in the case of HTTP status 5xx. UnknownHttpStatusCodeException – in the case of an unknown HTTP status.

Will RestTemplate be deprecated?

RestTemplate will still be used. But in some cases, the non-blocking approach uses much fewer system resources compared to the blocking one.

How do you use RestTemplate postForObject?

4.1. RestTemplate's postForObject method creates a new resource by posting an object to the given URI template. It returns the result as automatically converted to the type specified in the responseType parameter.

How do you use postForEntity RestTemplate?

Using postForEntity()Find the postForEntity method declaration from Spring doc. url: The URL to post the request. request: The object to be posted. responseType: The type of response body.


1 Answers

The IOException thrown from sun.net.www.protocol.http.HttpURLConnection which RestTemplate uses by default. Looking the source in grepcode, getInputStream() throws IOException if the HTTP status code is 4xx (for 404 or 410 it throws a more specific FileNotFoundException)

To get around this, you need to supply a different HttpURLConnection implementation via the ClientHttpRequestFactory that is used as a constructor parameter to RestTemplate, or injected into it with the requestFactory property. For example

 HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
 RestTemplate restTemplate = new RestTemplate(factory);

Doing this via Spring injection is an exercise left for the reader :-)

like image 82
djb Avatar answered Sep 27 '22 23:09

djb