Обработка исключений 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());
    }

Это вернет все ожидаемые результаты ответа.

Ответ 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;
}