복붙노트

[SPRING] 스프링 MVC - RestTemplate 출시 예외 HTTP 404 일이

SPRING

스프링 MVC - RestTemplate 출시 예외 HTTP 404 일이

나는 자원이 발견되지 않을 때 404 오류를 보내 휴식 서비스가있다. 여기 내 컨트롤러의 소스와 HTTP 404 보낼 예외입니다.

@Controller
@RequestMapping("/site")
public class SiteController
{

    @Autowired
    private IStoreManager storeManager;

    @RequestMapping(value = "/stores/{pkStore}", method = RequestMethod.GET, produces = "application/json")
    @ResponseBody
    public StoreDto getStoreByPk(@PathVariable long pkStore) {       
        Store s = storeManager.getStore(pkStore);
        if (null == s) {
            throw new ResourceNotFoundException("no store with pkStore : " + pkStore);
        }
        return StoreDto.entityToDto(s);       

    }
}

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException
{       
    private static final long serialVersionUID = -6252766749487342137L;    
    public ResourceNotFoundException(String message) {
        super(message);
    }    
}

때이 코드 RestTemplate로 전화를 시도 :

ResponseEntity<StoreDto> r = restTemplate.getForEntity(url, StoreDto.class, m);
 System.out.println(r.getStatusCode());
 System.out.println(r.getBody());

나는이 예외가 나타납니다

org.springframework.web.client.RestTemplate handleResponseError
ATTENTION: GET request for "http://........./stores/99" resulted in 404 (Introuvable); invoking error handler
org.springframework.web.client.HttpClientErrorException: 404 Introuvable

나는 내 responseEntity 개체를 탐색하고에 statusCode와 함께 몇 가지 일을 할 수있다 생각했다. 그러나 예외 출시하고 내 응용 프로그램 아래로 이동합니다.

예외를 보내하지만 내 ResponseEntity을 채우지 할 restTemplate에 대한 특정 구성이 있습니다.

도움을 주셔서 대단히 감사합니다.

--

루이

해결법

  1. ==============================

    1.지금까지 내가 알고 있어요, 당신은 실제 ResponseEntity을 얻을 수 있지만, 상태 코드와 바디 (있는 경우)를 제외하고 얻을 수 있습니다 :

    지금까지 내가 알고 있어요, 당신은 실제 ResponseEntity을 얻을 수 있지만, 상태 코드와 바디 (있는 경우)를 제외하고 얻을 수 있습니다 :

    try {
        ResponseEntity<StoreDto> r = restTemplate.getForEntity(url, StoreDto.class, m);
    }
    catch (final HttpClientErrorException e) {
        System.out.println(e.getStatusCode());
        System.out.println(e.getResponseBodyAsString());
    }
    
  2. ==============================

    2.RESTTemplate는 IMO이 분야에서 매우 부족하다. 오류를받은 경우에 당신이 가능하게 응답 본문을 추출 할 수있는 방법에 대해 여기 좋은 블로그 게시물이있다 :

    RESTTemplate는 IMO이 분야에서 매우 부족하다. 오류를받은 경우에 당신이 가능하게 응답 본문을 추출 할 수있는 방법에 대해 여기 좋은 블로그 게시물이있다 :

    http://springinpractice.com/2013/10/07/handling-json-error-object-responses-with-springs-resttemplate

    오늘로서 템플릿 응답 본문을 추출 할 수있는 가능성을 제공하는 뛰어난 JIRA 요청이있다 :

    https://jira.spring.io/browse/SPR-10961

    쪼그리고 곰의 답변과 문제는 당신이 404 년대에 대처하고자하는 경우 catch 블록 예 : 내부 상태 코드를 심문해야한다는 것입니다

    여기에 내가 내 마지막 프로젝트에이 문제를 가지고 방법입니다. 이 더 나은 방법 일 수 있으며, 내 솔루션은 모든위한 responseBody를 추출하지 않습니다.

    public class ClientErrorHandler implements ResponseErrorHandler
    {
       @Override
       public void handleError(ClientHttpResponse response) throws IOException 
       {
           if (response.getStatusCode() == HttpStatus.NOT_FOUND)
           {
               throw new ResourceNotFoundException();
           }
    
           // handle other possibilities, then use the catch all... 
    
           throw new UnexpectedHttpException(response.getStatusCode());
       }
    
       @Override
       public boolean hasError(ClientHttpResponse response) throws IOException 
       {
           return response.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR
             || response.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR;
       }
    

    ResourceNotFoundException 및 UnexpectedHttpException 내 자신의 체크되지 않은 예외입니다.

    다음은 나머지 템플릿을 생성 할 때 :

        RestTemplate template = new RestTemplate();
        template.setErrorHandler(new ClientErrorHandler());
    

    이제 우리는 요청을 할 때 구성 깔끔한 약간을 얻을 :

        try
        {
            HttpEntity response = template.exchange("http://localhost:8080/mywebapp/customer/100029",
                                            HttpMethod.GET, requestEntity, String.class);
            System.out.println(response.getBody());
        }
        catch (ResourceNotFoundException e)
        {
            System.out.println("Customer not found");
        }
    
  3. ==============================

    3.그것은 2018 년이고 나는 사람들이 "봄"을 말할 때 실제로 적어도 "봄 부팅"을 의미하는 희망 때문에, 나는 덜 먼지 덮인 접근 주어진 답을 확장하고 싶었다.

    그것은 2018 년이고 나는 사람들이 "봄"을 말할 때 실제로 적어도 "봄 부팅"을 의미하는 희망 때문에, 나는 덜 먼지 덮인 접근 주어진 답을 확장하고 싶었다.

    이전 답변에서 언급 한 모든 올 - 사용자 정의 ResponseErrorHandler를 사용해야합니다. 지금, 그것은을 구성하는 봄 부팅 세계에서 가장 좋은 방법은 이전보다 조금 더 간단합니다. RestTemplateBuilder라는 편리한 클래스가있다. 당신은 자바 문서의 첫 번째 라인을 읽을 경우는 말한다 :

    사실은 그냥하는 방법이있다 :

    new RestTemplateBuilder().errorHandler(new DefaultResponseErrorHandler()).build();
    

    그 위에, 봄 사람은 오래 전에 기존의 RestTemplate의 단점을 실현하고, 어떻게 테스트에서 특히 고통 스러울 수 있습니다. 그들은 RestTemplate의 래퍼 역할을하는 편리한 클래스, TestRestTemplate을 만들고 빈 구현의 ErrorHandler를 설정 :

    private static class NoOpResponseErrorHandler extends 
           DefaultResponseErrorHandler {
    
        @Override
        public void handleError(ClientHttpResponse response) throws IOException {
        }
    
    }
    
  4. ==============================

    4.당신은 예외를 throw하지 않습니다 자신의 RestTemplate 래퍼를 만들 수 있지만 수신 상태 코드로 응답을 반환 할 수 있습니다. (당신은 또한 몸을 반환 할 수 있지만 그 형태 보증 그만 것, 그래서 몸 아래 코드는 단순히 null이 남아있다.)

    당신은 예외를 throw하지 않습니다 자신의 RestTemplate 래퍼를 만들 수 있지만 수신 상태 코드로 응답을 반환 할 수 있습니다. (당신은 또한 몸을 반환 할 수 있지만 그 형태 보증 그만 것, 그래서 몸 아래 코드는 단순히 null이 남아있다.)

    /**
     * A Rest Template that doesn't throw exceptions if a method returns something other than 2xx
     */
    public class GracefulRestTemplate extends RestTemplate {
        private final RestTemplate restTemplate;
    
        public GracefulRestTemplate(RestTemplate restTemplate) {
            super(restTemplate.getMessageConverters());
            this.restTemplate = restTemplate;
        }
    
        @Override
        public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException {
            return withExceptionHandling(() -> restTemplate.getForEntity(url, responseType));
        }
    
        @Override
        public <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException {
            return withExceptionHandling(() -> restTemplate.postForEntity(url, request, responseType));
        }
    
        private <T> ResponseEntity<T> withExceptionHandling(Supplier<ResponseEntity<T>> action) {
            try {
                return action.get();
            } catch (HttpClientErrorException ex) {
                return new ResponseEntity<>(ex.getStatusCode());
            }
        }
    }
    
  5. ==============================

    5.최근 이것에 대한 사용 사례가 있었다. 내 솔루션 :

    최근 이것에 대한 사용 사례가 있었다. 내 솔루션 :

    public class MyErrorHandler implements ResponseErrorHandler {
    
    @Override
    public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
        return hasError(clientHttpResponse.getStatusCode());
    }
    
    @Override
    public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
        HttpStatus statusCode = clientHttpResponse.getStatusCode();
        MediaType contentType = clientHttpResponse
            .getHeaders()
            .getContentType();
        Charset charset = contentType != null ? contentType.getCharset() : null;
        byte[] body = FileCopyUtils.copyToByteArray(clientHttpResponse.getBody());
    
        switch (statusCode.series()) {
            case CLIENT_ERROR:
                throw new HttpClientErrorException(statusCode, clientHttpResponse.getStatusText(), body, charset);
            case SERVER_ERROR:
                throw new HttpServerErrorException(statusCode, clientHttpResponse.getStatusText(), body, charset);
            default:
                throw new RestClientException("Unknown status code [" + statusCode + "]");
        }
    
    }
    
    private boolean hasError(HttpStatus statusCode) {
        return (statusCode.series() == HttpStatus.Series.CLIENT_ERROR ||
            statusCode.series() == HttpStatus.Series.SERVER_ERROR);
    }
    
  6. from https://stackoverflow.com/questions/16194014/spring-mvc-resttemplate-launch-exception-when-http-404-happens by cc-by-sa and MIT license