ClientHttpResponse.getBody () throws a ResourceAccessException when the response code is 401

I am trying to register request-response pairs for each request. The problem is that when the response code is 401 , ClientHttpResponse.getBody() throws a ResourceAccessException and I cannot read the body of the response.

This is a RestTemplate configuration

 RestTemplate restTemplate = new RestTemplate(); // Added this requestFactory to make response object readable more than once. ClientHttpRequestFactory requestFactory = new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()); restTemplate.setRequestFactory(requestFactory); restTemplate.getInterceptors().add(new RequestLoggingInterceptor(vCloudRequest.getAction(),httpHeaders)); restTemplate.setErrorHandler(new RequestErrorHandler()); return restTemplate; 

The last line of the interceptor below raises the following exception.

How can I solve this problem?

org.springframework.web.client.ResourceAccessException: I / O error POST request for " https://example.com/api/sessions ": server returned HTTP response code: 401 for URL: https://example.com/api / sessions ; The nested exception is java.io.IOException: the server responded with an HTTP response code: 401 for URL: https: //example.com.11/api/sessions

This is a related part of the interceptor.

 @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { ClientHttpResponse response = execution.execute(request, body); String requestString = new String(body); // Calling this method because when we make a POST or PUT request and get an error // response.getBody() throws IOException. But if we call response.getStatusCode() it works fine. // I don't know the reason. // I asked a question on stackoverflow // https://stackoverflow.com/questions/47429978/resttemplate-response-getbody-throws-exception-on-4-and-5-errors-for-put-and response.getStatusCode(); String responseString = new String(ByteStreams.toByteArray(response.getBody()), Charset.forName("UTF-8")); ... } 

This is a custom error handler.

Public class RequestErrorHandler implements ResponseErrorHandler {

 @Override public boolean hasError(ClientHttpResponse response) throws IOException { if (!response.getStatusCode().is2xxSuccessful()) { return true; } return false; } @Override public void handleError(ClientHttpResponse response) throws IOException { JAXBElement<ErrorType> root = null; try { JAXBContext jaxbContext = JAXBContext.newInstance(ErrorType.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); root = jaxbUnmarshaller.unmarshal(new StreamSource( response.getBody()), ErrorType.class); } catch (JAXBException e) { throw new IOException("XML converting error. Cannot convert response to ErrorType"); } ErrorType error = root.getValue(); throw new VcloudException(error); } } 
+5
source share
4 answers

Spring RestTemplate by default generates an error when httpstatus is not 200.

In my last project, I did to add a custom org.springframework.web.client.ResponseErrorHandler to the template for the rest. You can write a class like this:

 public class SimpleRestErrorHandler implements ResponseErrorHandler { private static final Logger logger = LoggerFactory.getLogger(SimpleRestErrorHandler.class.getName()); @Override public boolean hasError(ClientHttpResponse response) throws IOException { int statusCode = response.getStatusCode().value(); if( logger.isDebugEnabled() ) { logger.debug("STATUS CODE ["+statusCode+"] "); } //Generate Error only when HTTP Status code is 500 if( statusCode == 500 ) { return true; } return false; } @Override public void handleError(ClientHttpResponse response) throws IOException { //Here you can manage the error (in this sample only the http status code = 500 } } 

Then I added this to the rest pattern:

XML configuration example

 <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"> <constructor-arg ref="bufferingClientHttpRequestFactory" /> <property name="errorHandler" ref="simpleRestErrorHandler" /> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg value="#{T(java.nio.charset.Charset).forName('UTF-8')}" /> </bean> <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" /> <bean class="org.springframework.http.converter.ResourceHttpMessageConverter" /> <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" /> <bean class="org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter" /> <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" /> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /> </list> </property> <property name="interceptors"> <!-- Custom interceptors --> </property> </bean> <bean id="bufferingClientHttpRequestFactory" name="bufferingClientHttpRequestFactory" class="org.springframework.http.client.BufferingClientHttpRequestFactory"> <constructor-arg ref="simpleReqFact" /> </bean> <bean id="simpleRestErrorHandler" class="handlers.SimpleRestErrorHandler" /> 

Java configuration

 @Config public class restTemplConfig { @Bean public RestTemplate restTempl() { RestTemplate result = new RestTemplate(); //Add converters //Add custom error handler result.setErrorHandler(new SimpleRestErrorHandler()); } } 

I hope this is helpful

0
source

I do not think that a ResourceAccessException thrown by response.getBody() , instead it seems that ByteStreams.toByteArray(...) is probably sending a null stream in response.

Try debugging if response.getBody() is null or ByteStreams.toByteArray() . Because a RescourceAccessException occurs when an I / O error occurs.

0
source

Use HttpComponentsClientHttpRequestFactory instead of SimpleClientHttpRequestFactory.

Also add the dependency to 'org.apache.httpcomponents: httpclient.

HttpComponentsClientHttpRequestFactory can view the body at status 401.

0
source
 public class RestTemplate extends InterceptingHttpAccessor implements RestOperations 

Spring is the central class for client-side synchronous HTTP access. This simplifies communication with HTTP servers and provides RESTful principles. It handles HTTP connections, leaving the application code to provide URLs (with possible template variables) and retrieve the results. Note. By default, RestTemplate uses the standard JDK features to establish HTTP connections. You can switch to using another HTTP protocol library such as Apache HttpComponents, Netty and OkHttp through the InterceptingHttpAccessor.setRequestFactory (org.springframework.http.client.ClientHttpRequestFactory) property.

The main entry points to this template are methods named after the six basic HTTP methods:

HTTP Method RestTemplate Methods

  • DELETE delete (java.lang.String, java.lang.Object ...)
  • GET getForObject (java.lang.String, java.lang.Class, java.lang.Object ...) getForEntity (java.lang.String, java.lang.Class, java.lang.Object ...)
  • HEAD headForHeaders (java.lang.String, java.lang.Object ...)
  • OPTIONS optionsForAllow (java.lang.String, java.lang.Object ...)
  • POST postForLocation (java.lang.String, java.lang.Object, java.lang.Object ...) postForObject (java.lang.String, java.lang.Object, java.lang.Class, java.lang.Object. ..)
  • PUT put (java.lang.String, java.lang.Object, java.lang.Object ...)
  • any exchange (java.lang.String, org.springframework.http.HttpMethod, org.springframework.http.HttpEntity, java.lang.Class, java.lang.Object ...) execute (java.lang.String, org. springframework.http.HttpMethod, org.springframework.web.client.RequestCallback, org.springframework.web.client.ResponseExtractor, java.lang.Object ...)

RestTemplate


 public class ResponseEntity<T> extends HttpEntity<T> 

An HttpEntity extension that adds an HttpStatus status code. It is also used in RestTemplate @Controller methods.

ResponseEntity


Use RestTemplate methods and use ResponseEntity.

Code example:

 @Override public ResponseEntity<?> callLocalGeo(double lat, double lng) { String url = "https://apis.sample.net/local/geo/coord2addr?apiKey=" + this.key + "&longitude=" + lng + "&latitude=" + lat + "&output=json"; RestTemplate rest = new RestTemplate(); try { // success return rest.getForEntity(url, String.class); } catch (HttpStatusCodeException e) { // new Error Response return ResponseEntity.status(e.getStatusCode()).headers(e.getResponseHeaders()) .body(e.getResponseBodyAsString()); } } 

REST Call API

 ResponseEntity<?> respEntity = sampleService.callLocalGeo(lat, lng); if (HttpStatus.OK.equals(respEntity.getStatusCode())) { String respBody = (String) respEntity.getBody(); // something... } else { // error handling... } 

RestTemplate Example


ClientHttpRequestInterceptor

Editing RestTemplate configuration.

 RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory())); List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>(); // add your interceptor. interceptors.add(new RequestLoggingInterceptor()); restTemplate.setInterceptors(interceptors); 

Editing your interceptor.

 @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { ClientHttpResponse response = execution.execute(request, body); StringBuilder stringBuilder = new StringBuilder(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), "UTF-8")); String line = null; while ((line = bufferedReader.readLine()) != null) { stringBuilder.append(line); stringBuilder.append('\n'); } // using response body. log.debug("Response body: ", stringBuilder.toString()); } 
-2
source

Source: https://habr.com/ru/post/1276080/


All Articles