developer tip

Spring Resttemplate 예외 처리

copycodes 2020. 9. 18. 08:19
반응형

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에서 래핑해야합니까? 그렇다면 코드의 목적은 무엇일까요?


구현하는 클래스를 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 오류를 처리하는 방법에 대한 아이디어를 얻으 려면 소스 코드살펴보십시오 .


HttpStatusCodeException예외를 포착해야합니다 .

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

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

그러면 응답에서 예상되는 모든 결과가 반환됩니다.


또 다른 해결책은 "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 
}

이 튜토리얼이나 다른 튜토리얼 중 어느 것도 나를 위해 일하지 않았습니다. RestTemplate은 단순히 쓰레기입니다. 다른 사람들이이 끔찍한 일에 시간을 낭비하지 않도록 고려하도록이 글을 쓰고 있습니다. restTemplate.exchange를 호출하고 400 상태 코드를 얻습니다. 예외도 해당 줄에서 throw되지만 HttpStatusCodeException이 아니라 ResourceAccessException입니다. 나는 Object와 String을 교환하려고 시도했습니다. 나는 완전히 쓸모없는 ResponseErrorHandler를 포함하려고 시도했습니다.

RestTemplate으로 원하는 것을 할 수없는 것도 처음이 아니며 오랫동안 사용하지도 않았습니다. 시간을 낭비하지 마십시오.

예를 들어 다음을 사용할 수 있습니다.

Apache HttpClient : https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient

또는 OkHttp3 : https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp


Spring은 매우 큰 http 상태 코드 목록에서 당신을 추상화합니다. 그것이 예외의 개념입니다. org.springframework.web.client.RestClientException 계층 구조를 살펴보십시오.

http 응답을 처리 할 때 가장 일반적인 상황을 매핑하는 많은 클래스가 있습니다. http 코드 목록은 매우 커서 각 상황을 처리하는 코드를 작성하고 싶지 않을 것입니다. 그러나 예를 들어 HttpClientErrorException 하위 계층 구조를 살펴보십시오. 4xx 종류의 오류를 매핑하는 단일 예외가 있습니다. 깊이 들어가야한다면 할 수 있습니다. 그러나 HttpClientErrorException을 포착하기 만하면 서비스에 잘못된 데이터가 제공된 모든 상황을 처리 할 수 ​​있습니다.

DefaultResponseErrorHandler는 정말 간단하고 견고합니다. 응답 상태 코드가 2xx 계열이 아닌 경우 hasError 메서드에 대해 true를 반환합니다.


에서 풀링 (http 클라이언트 팩토리) 또는로드 밸런싱 (유레카) 메커니즘을 사용 RestTemplate하는 new RestTemplate경우 클래스별로 생성 할 있는 사치가 없습니다 . 두 개 이상의 서비스를 호출하는 setErrorHandler경우 모든 요청에 ​​대해 전역 적으로 사용 되므로 사용할 수 없습니다 .

이 경우 잡는 HttpStatusCodeException것이 더 나은 옵션 인 것 같습니다.

유일한 다른 옵션 RestTemplate@Qualifier주석을 사용하여 여러 인스턴스 를 정의하는 것 입니다.

또한-그러나 이것은 내 취향입니다-나는 내 호출에 단단히 묶여있는 내 오류 처리를 좋아합니다.


교환 코드는 다음과 같습니다 .

public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
            HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException

예외 RestClientExceptionHttpClientErrorException있고 HttpStatusCodeException예외입니다.

그렇게 RestTemplete이 발생 시킬수 있습니다 HttpClientErrorExceptionHttpStatusCodeException예외입니다. 예외 개체에서 다음과 같은 방법으로 정확한 오류 메시지를 얻을 수 있습니다.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);

마지막으로 exchange 메소드를 호출해야합니다.

ResponseEntity<?> responseEntity = restTemplate.exchange(url, httpMethod, entity, responseObject);

prety 인쇄를 위해 Gson 라이브러리를 사용했습니다. 여기 gradle이 있습니다.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);
    }
}

감사 :)


다음은 모든 유형의 잘못된 응답에 대한 응답 본문을 반환하는 HTTPS를 사용하는 내 POST 메서드입니다.

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

참고URL : https://stackoverflow.com/questions/38093388/spring-resttemplate-exception-handling

반응형