【发布时间】:2012-09-15 05:40:15
【问题描述】:
RestTemplate 的方法如postForEntity() 抛出RestClientException。我想从 catch 块中的异常对象中提取 HTTP 状态代码和响应正文。我该怎么做?
【问题讨论】:
标签: java resttemplate
RestTemplate 的方法如postForEntity() 抛出RestClientException。我想从 catch 块中的异常对象中提取 HTTP 状态代码和响应正文。我该怎么做?
【问题讨论】:
标签: java resttemplate
不要捕捉RestClientException,而是捕捉特殊的HttpClientErrorException。
这是一个例子:
try {
Link dataCenterLink = serviceInstance.getLink("dataCenter");
String dataCenterUrl = dataCenterLink.getHref();
DataCenterResource dataCenter =
restTemplate.getForObject(dataCenterUrl, DataCenterResource.class);
serviceInstance.setDataCenter(dataCenter);
} catch (HttpClientErrorException e) {
HttpStatus status = e.getStatusCode();
if (status != HttpStatus.NOT_FOUND) { throw e; }
}
HttpClientErrorException 提供getStatusCode 和getResponseBodyAsByteArray 分别获取状态码和正文。
【讨论】:
HttpStatusCodeException,由HttpClientErrorException和HttpServerErrorException继承。
HttpStatusCodeException,你就可以访问方法getResponseBodyAsString()。
在某些情况下,不会抛出 HttpClientErrorException。比如下面的方法restTemplate.exchange调用:
ResponseEntity<Employee[]> employees = restTemplate.exchange(url, HttpMethod.GET, entity, Employee[].class);
获取 http 正文并将其编组到实体。如果远程资源返回一个罕见的错误,则内部编组不起作用,只会抛出 RestClientException。
在这种情况下,或者如果您想处理 restTemplate 操作中的任何错误,您可以使用 setErrorHandler。这个方法接收一个基本的 ResponseErrorHandler 和有用的方法。
这个方法hasError让我可以获取远程http正文并帮助我检测调用的错误或者远程http远程资源中的错误:
restTemplate.setErrorHandler(new ResponseErrorHandler() {
@Override
public boolean hasError(ClientHttpResponse arg0) throws IOException {
System.out.println("StatusCode from remote http resource:"+arg0.getStatusCode());
System.out.println("RawStatusCode from remote http resource:"+arg0.getRawStatusCode());
System.out.println("StatusText from remote http resource:"+arg0.getStatusText());
String body = new BufferedReader(new InputStreamReader(arg0.getBody()))
.lines().collect(Collectors.joining("\n"));
System.out.println("Error body from remote http resource:"+body);
return false;
}
@Override
public void handleError(ClientHttpResponse arg0) throws IOException {
// do something
}
});
此外,您可以手动评估正文或状态并返回 true 或 false 以标记为错误与否。
【讨论】:
改为使用RestClientResponseException。它更通用。
来自docs:包含实际 HTTP 响应数据的异常的通用基类。
【讨论】:
private void sendActivity(StatsActivity statsActivity) throws InterruptedException
{
LibraryConnectorXapiEditView libraryConnectorXapiEditView = (LibraryConnectorXapiEditView) workerBundle.getConnector();
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Statement statement = libraryConnectorConverter.convertActivityToStatement(statsActivity, workerBundle);
HttpEntity<Statement> request = new HttpEntity<>(statement, headers);
try
{
String lrsEndPoint = libraryConnectorXapiEditView.getLrsEndPoint() + "/statements";
ResponseEntity<String> response = restTemplate.exchange(lrsEndPoint, HttpMethod.POST, request, String.class);
ocnCompletionEventDao.save(this.convertToOcnCompletionEvent(statsActivity, response.getBody(), response.getStatusCodeValue()));
}
catch (HttpClientErrorException ex)
{
ocnCompletionEventDao.save(this.convertToOcnCompletionEvent(statsActivity, ex.getResponseBodyAsString(), ex.getStatusCode().value()));
checkResponse(ex, libraryConnectorXapiEditView);
if(failedAttempts<3)
{
sendActivity(statsActivity);
failedAttempts++;
}
}
}
private void checkResponse(HttpClientErrorException ex, LibraryConnectorXapiEditView libraryConnectorXapiEditView) throws InterruptedException
{
int statusCode = ex.getStatusCode().value();
int retryAfterSeconds = retryAfter(ex.getResponseHeaders());
switch (statusCode)
{
case 401:
headers = xApiAuthorizationUtils.getHeaders(libraryConnectorXapiEditView);
case 429:
if(retryAfterSeconds!=0)
Thread.sleep(retryAfterSeconds);
case 422:
failedAttempts=3;
}
}
【讨论】: