RestTemplate - Handling response headers/body in Exceptions (RestClientException, HttpStatusCodeException)
Asked Answered
E

3

31

In my restful webservice, in case of bad request (5xx) or 4xx respose codes, I write a custom header "x-app-err-id" to the response.

On the client side, I use exchange method of RestTemplate to make a RestFul web service call. Everything is fine when the response code is 2xx.

ResponseEntity<Component> response = restTemplate.exchange(webSvcURL,
    HttpMethod.POST, 
    requestEntity,
    Component.class);

But if there is an exception(HttpStatusCodeException) because of it being a bad request(5xx) or 4xx, in the catch block of HttpStatusCodeException, I get response(see above) as null and so I do not have access to my custom header I set in my web service. How do I get custom headers from the response in case of exceptions in RestTemplate.

One more question is, I set an error object(json) in the reponse body in case of error and I would like to know how to access response body as well in case of exceptions in RestTemplate

Eleni answered 24/10, 2011 at 15:26 Comment(0)
E
33

I finally did it using ResponseErrorHandler.

public class CustomResponseErrorHandler implements ResponseErrorHandler {

    private static ILogger logger = Logger.getLogger(CustomResponseErrorHandler.class);

    private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler();

    public void handleError(ClientHttpResponse response) throws IOException {

        List<String> customHeader = response.getHeaders().get("x-app-err-id");

        String svcErrorMessageID = "";
        if (customHeader != null) {
            svcErrorMessageID = customHeader.get(0);                
        }

        try {           

            errorHandler.handleError(response);

        } catch (RestClientException scx) {         

            throw new CustomException(scx.getMessage(), scx, svcErrorMessageID);
        }
    }

    public boolean hasError(ClientHttpResponse response) throws IOException {
        return errorHandler.hasError(response);
    }
}

And then use this custom response handler for RestTemplate by configuring as shown below

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
   <property name="messageConverters">
       <list>
           <ref bean="jsonConverter" />
       </list>
   </property>    
   <property name="errorHandler" ref="customErrorHandler" />
</bean>

<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
   <property name="supportedMediaTypes" value="application/json" />
</bean>

<bean id="customErrorHandler " class="my.package.CustomResponseErrorHandler">
</bean>
Eleni answered 28/10, 2011 at 2:2 Comment(2)
you could extend DefaultResponseErrorHandler instead of implementing ResponseErrorHandler and creating instance of DefaultResponseErrorHanlder.Enravish
did you manage to read body from erroneous request (like from 401,403,404 etc.) ?Apprehensible
T
30

You shouldn't have to create a custom error handler. You can get the body and headers from the HttpStatusCodeException that gets thrown.

try {
    ResponseEntity<Component> response = restTemplate.exchange(webSvcURL,
        HttpMethod.POST, 
        requestEntity,
        Component.class);
} catch (HttpStatusCodeException e) {
    List<String> customHeader = e.getResponseHeaders().get("x-app-err-id");
    String svcErrorMessageID = "";
    if (customHeader != null) {
        svcErrorMessageID = customHeader.get(0);                
    }
    throw new CustomException(e.getMessage(), e, svcErrorMessageID);
    // You can get the body too but you will have to deserialize it yourself
    // e.getResponseBodyAsByteArray()
    // e.getResponseBodyAsString()
}
Tumbler answered 25/3, 2016 at 20:28 Comment(0)
B
0

If you use a global exception handler add the below method or check this

https://www.javaguides.net/2018/09/spring-boot-2-exception-handling-for-rest-apis.html add below method in GlobalExceptionHandler class

@ExceptionHandler({HttpClientErrorException.class, HttpStatusCodeException.class, HttpServerErrorException.class})
    @ResponseBody
    public ResponseEntity<Object> httpClientErrorException(HttpStatusCodeException e) throws IOException {
        BodyBuilder bodyBuilder = ResponseEntity.status(e.getRawStatusCode()).header("X-Backend-Status", String.valueOf(e.getRawStatusCode()));
        if (e.getResponseHeaders().getContentType() != null) {
            bodyBuilder.contentType(e.getResponseHeaders().getContentType());
        }
        return bodyBuilder.body(e.getResponseBodyAsString());
    }
Boomerang answered 30/11, 2021 at 1:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.