Reputation: 1607
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
Upvotes: 31
Views: 50467
Reputation: 83
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());
}
Upvotes: 0
Reputation: 7315
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()
}
Upvotes: 30
Reputation: 1607
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>
Upvotes: 33