2013-04-24 89 views
12

我有一個休息服務,當找不到資源時發送404錯誤。 這裏我控制器的來源和發送異常HTTP 404。Spring MVC - 發生http 404時RestTemplate啓動異常

@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做一些事情。但例外是啓動和我的應用程序下降。

是否有restTemplate不發送異常但填充我的ResponseEntity的特定配置。

非常感謝您的幫助。

-

盧瓦克

+0

能夠通過瀏覽器來訪問其他服務?或者那還扔404? – Akshay 2013-04-24 15:18:00

+0

你有沒有找到答案? – leojh 2014-02-04 20:22:11

回答

21

據我所知,你不能得到實際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()); 
    } 
11

RESTTemplate在這方面的IMO相當不足。有一個很好的博客文章在這裏你如何當你收到一個錯誤可能可能提取響應正文:

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

截至今天存在,模板提供了可能提取一個優秀的JIRA請求響應體:

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

與蹲便器熊回答麻煩的是,你必須詢問狀態代碼catch塊例如裏面,如果你只想要對付404的

下面是我在最後一個項目中解決這個問題的方法。可能有更好的方法,我的解決方案根本不提取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 
    { 
     if ((response.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR) 
     || (response.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR)) 
     { 
      return true; 
     } 
     return false; 
    } 

}

的ResourceNotFoundException和UnexpectedHttpException是我自己的unchecked異常。

的創建其餘的模板時:

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"); 
    } 
+0

設置處理程序後,您實際上不需要try ... catch部分。 – eosimosu 2017-08-26 12:57:30

+0

設置處理程序後try..catch部分是什麼? ResourceNotFoundException?這是我自己的異常類型,我不需要它,但我需要它。 – 2017-08-29 12:43:27

+0

是的,有道理 – eosimosu 2017-08-29 12:45:14

0

最近有這個一個用例。我的解決辦法:

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

您可以創建自己的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()); 
     } 
    } 
}