it-roy-ru.com

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]

Неужели мне нужно обернуть остальные методы обмена шаблонами в try? Какова будет тогда цель кодов?

71
vaibhav

Вы хотите создать класс, который реализует 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.

87
carcaret

Вы должны поймать исключение HttpStatusCodeException:

try {
    restTemplate.exchange(...);
} catch (HttpStatusCodeException exception) {
    int statusCode = exception.getStatusCode().value();
    ...
}
24
mekazu

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());
    }

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

11
austin cherlo

Другое решение, описанное здесь в конце этой статьи "enlian": http://springinpractice.com/2013/10/07/handling-json-error-object-responses-with-springs -стремплет

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 
}
4
Investigator

Ни один из этих или других уроков в другом месте не работал для меня. 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

2
Siamaster

Если вы используете пул (фабрика клиента http) или механизм распределения нагрузки (eureka) с вашим RestTemplate, вы не сможете позволить себе создать new RestTemplate для каждого класса. Если вы звоните в несколько служб, вы не можете использовать setErrorHandler, потому что if будет использоваться глобально для всех ваших запросов. 

В этом случае перехват HttpStatusCodeException кажется лучшим вариантом.

Единственный другой вариант, который у вас есть, - это определить несколько экземпляров RestTemplate, используя аннотацию @Qualifier.

Кроме того - но это мой собственный вкус - мне нравится, когда моя обработка ошибок тесно связана с моими вызовами. 

1
Hannes

Код обмена ниже :

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);
    }
}

Спасибо :)

0
Md. Sajedul Karim

Spring абстрагирует вас от очень-очень большого списка http-кода статуса. Это идея исключений. Взгляните на иерархию org.springframework.web.client.RestClientException:

 

У вас есть куча классов для отображения наиболее распространенных ситуаций при работе с http-ответами. Список кодов http действительно большой, вам не нужно писать код для каждой ситуации. Но, например, взгляните на иерархию HttpClientErrorException. У вас есть одно исключение для сопоставления с любой ошибкой 4xx. Если вам нужно углубиться, тогда вы можете. Но просто перехватывая исключение HttpClientErrorException, вы можете справиться с любой ситуацией, когда службе были предоставлены неверные данные.

DefaultResponseErrorHandler действительно простой и надежный. Если код состояния ответа не относится к семейству 2xx, он просто возвращает true для метода hasError.

0
Perimosh