Обработка исключений Spring Resttemplate
Ниже приведен фрагмент кода; в основном, я пытаюсь распространять исключение, когда код ошибки составляет не более 200.
ResponseEntity<Object> response = restTemplate.exchange(url.toString().replace("{version}", version),
HttpMethod.POST, entity, Object.class);
if(response.getStatusCode().value()!= 200){
logger.debug("Encountered Error while Calling API");
throw new ApplicationException();
}
Однако в случае ответа 500 с сервера я получаю исключение
org.springframework.web.client.HttpServerErrorException: 500 Internal Server Error
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94) ~[spring-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
Мне действительно нужно обернуть метод обмена шаблонами остальных в попытке? Что тогда будет целью кодов?
Ответы
Ответ 1
Вы хотите создать класс, который реализует ResponseErrorHandler
, а затем использовать его экземпляр, чтобы установить обработку ошибок вашего шаблона отдыха:
public class MyErrorHandler implements ResponseErrorHandler {
@Override
public void handleError(ClientHttpResponse response) throws IOException {
// your error handling here
}
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
...
}
}
[...]
public static void main(String args[]) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new MyErrorHandler());
}
Кроме того, в Spring есть класс DefaultResponseErrorHandler
, который вы можете расширить вместо реализации интерфейса, если хотите переопределить только метод handleError
.
public class MyErrorHandler extends DefaultResponseErrorHandler {
@Override
public void handleError(ClientHttpResponse response) throws IOException {
// your error handling here
}
}
Взгляните на его исходный код, чтобы понять, как Spring обрабатывает ошибки HTTP.
Ответ 2
Вы должны поймать исключение HttpStatusCodeException
:
try {
restTemplate.exchange(...);
} catch (HttpStatusCodeException exception) {
int statusCode = exception.getStatusCode().value();
...
}
Ответ 3
Spring умело рассматривает коды ошибок HTTP как исключения и предполагает, что ваш код обработки исключений имеет контекст для обработки ошибки. Чтобы получить обмен, чтобы функционировать так, как вы ожидали, сделайте следующее:
try {
return restTemplate.exchange(url, httpMethod, httpEntity, String.class);
} catch(HttpStatusCodeException e) {
return ResponseEntity.status(e.getRawStatusCode()).headers(e.getResponseHeaders())
.body(e.getResponseBodyAsString());
}
Это вернет все ожидаемые результаты ответа.
Ответ 4
Другое решение, описанное здесь в конце этого поста "enlian": http://springinpractice.com/2013/10/07/handling-json-error-object-responses-with-springs-resttemplate
try{
restTemplate.exchange(...)
} catch(HttpStatusCodeException e){
String errorpayload = e.getResponseBodyAsString();
//do whatever you want
} catch(RestClientException e){
//no response payload, tell the user sth else
}
Ответ 5
Ни один из этих или других уроков в другом месте не работал для меня. RestTemplate - это просто дерьмо. Я пишу это, чтобы другие думали не тратить время на эту ужасную вещь.
Я звоню restTemplate.exchange и получаю 400 кодов статуса. В этой строке также выдается исключение, но это не исключение HttpStatusCodeException, а ResourceAccessException. Я попытался обменять на объект и строку. Я попытался включить ResponseErrorHandler, который совершенно бесполезен.
Это не первый раз, когда я не могу делать то, что я хочу с RestTemplate, и я даже не использовал это в течение длительного времени. Не трать время.
Вы можете, например, использовать:
Apache HttpClient:
https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient
Или же
OkHttp3:https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
Ответ 6
Spring абстрагирует вас от очень-очень большого списка http-кода статуса. Это идея исключений. Ознакомьтесь с иерархией org.springframework.web.client.RestClientException:
У вас есть куча классов для отображения наиболее распространенных ситуаций при работе с http-ответами. Список кодов http действительно большой, вам не нужно писать код для каждой ситуации. Но, например, взгляните на иерархию HttpClientErrorException. У вас есть одно исключение для сопоставления с любой ошибкой 4xx. Если вам нужно углубиться, тогда вы можете. Но просто перехватывая исключение HttpClientErrorException, вы можете справиться с любой ситуацией, когда службе были предоставлены неверные данные.
DefaultResponseErrorHandler действительно простой и надежный. Если код состояния ответа не относится к семейству 2xx, он просто возвращает true для метода hasError.
Ответ 7
Если вы используете механизм объединения (http client factory) или механизм балансировки нагрузки (eureka) с вашим RestTemplate
, у вас не будет роскоши создавать new RestTemplate
каждого класса. Если вы вызываете более одной службы, вы не можете использовать setErrorHandler
потому что если бы глобально использовался для всех ваших запросов.
В этом случае лучше всего использовать HttpStatusCodeException
.
Единственный другой вариант, который у вас есть, - это определить несколько экземпляров RestTemplate
с @Qualifier
аннотации @Qualifier
.
Кроме того - но это мой собственный вкус - мне нравится, как моя обработка ошибок плотно прижалась к моим звонкам.
Ответ 8
Код обмена указан ниже:
public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException
Исключение RestClientException
имеет исключение HttpClientErrorException
и HttpStatusCodeException
.
Поэтому в RestTemplete
могут возникать исключения HttpClientErrorException
и HttpStatusCodeException
.
В объекте исключения вы можете получить точное сообщение об ошибке следующим образом: exception.getResponseBodyAsString()
Вот пример кода:
public Object callToRestService(HttpMethod httpMethod, String url, Object requestObject, Class<?> responseObject) {
printLog( "Url : " + url);
printLog( "callToRestService Request : " + new GsonBuilder().setPrettyPrinting().create().toJson(requestObject));
try {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Object> entity = new HttpEntity<>(requestObject, requestHeaders);
long start = System.currentTimeMillis();
ResponseEntity<?> responseEntity = restTemplate.exchange(url, httpMethod, entity, responseObject);
printLog( "callToRestService Status : " + responseEntity.getStatusCodeValue());
printLog( "callToRestService Body : " + new GsonBuilder().setPrettyPrinting().create().toJson(responseEntity.getBody()));
long elapsedTime = System.currentTimeMillis() - start;
printLog( "callToRestService Execution time: " + elapsedTime + " Milliseconds)");
if (responseEntity.getStatusCodeValue() == 200 && responseEntity.getBody() != null) {
return responseEntity.getBody();
}
} catch (HttpClientErrorException exception) {
printLog( "callToRestService Error :" + exception.getResponseBodyAsString());
//Handle exception here
}catch (HttpStatusCodeException exception) {
printLog( "callToRestService Error :" + exception.getResponseBodyAsString());
//Handle exception here
}
return null;
}
Вот описание кода:
В этом методе вы должны передать запрос и класс ответа. Этот метод автоматически анализирует ответ как запрошенный объект.
Прежде всего, вы должны добавить конвертер сообщений.
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
Затем вы должны добавить requestHeader
.
Вот код:
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Object> entity = new HttpEntity<>(requestObject, requestHeaders);
Наконец, вы должны вызвать метод обмена:
ResponseEntity<?> responseEntity = restTemplate.exchange(url, httpMethod, entity, responseObject);
Для предварительной печати я использовал библиотеку Gson.
вот этот выпускник: compile 'com.google.code.gson:gson:2.4'
Вы можете просто позвонить по указанному ниже коду, чтобы получить ответ:
ResponseObject response=new RestExample().callToRestService(HttpMethod.POST,"URL_HERE",new RequestObject(),ResponseObject.class);
Вот полный рабочий код:
import com.google.gson.GsonBuilder;
import org.springframework.http.*;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;
public class RestExample {
public RestExample() {
}
public Object callToRestService(HttpMethod httpMethod, String url, Object requestObject, Class<?> responseObject) {
printLog( "Url : " + url);
printLog( "callToRestService Request : " + new GsonBuilder().setPrettyPrinting().create().toJson(requestObject));
try {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Object> entity = new HttpEntity<>(requestObject, requestHeaders);
long start = System.currentTimeMillis();
ResponseEntity<?> responseEntity = restTemplate.exchange(url, httpMethod, entity, responseObject);
printLog( "callToRestService Status : " + responseEntity.getStatusCodeValue());
printLog( "callToRestService Body : " + new GsonBuilder().setPrettyPrinting().create().toJson(responseEntity.getBody()));
long elapsedTime = System.currentTimeMillis() - start;
printLog( "callToRestService Execution time: " + elapsedTime + " Milliseconds)");
if (responseEntity.getStatusCodeValue() == 200 && responseEntity.getBody() != null) {
return responseEntity.getBody();
}
} catch (HttpClientErrorException exception) {
printLog( "callToRestService Error :" + exception.getResponseBodyAsString());
//Handle exception here
}catch (HttpStatusCodeException exception) {
printLog( "callToRestService Error :" + exception.getResponseBodyAsString());
//Handle exception here
}
return null;
}
private void printLog(String message){
System.out.println(message);
}
}
Спасибо :)
Ответ 9
Вот мой метод POST с HTTPS, который возвращает тело ответа для любого типа плохих ответов.
public String postHTTPSRequest(String url,String requestJson)
{
//SSL Context
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
//Initiate REST Template
RestTemplate restTemplate = new RestTemplate(requestFactory);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//Send the Request and get the response.
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
ResponseEntity<String> response;
String stringResponse = "";
try {
response = restTemplate.postForEntity(url, entity, String.class);
stringResponse = response.getBody();
}
catch (HttpClientErrorException e)
{
stringResponse = e.getResponseBodyAsString();
}
return stringResponse;
}