2013-04-24 82 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()); 
     } 
    } 
}