RestTemplate如何获取HTTP状态码
作者:搬甎小犟
文章介绍了使用RestTemplate请求接口并处理HTTP状态码的方法,为了解决默认处理器抛出异常的问题,建议自定义ResponseErrorHandler,自定义处理器不会抛出异常,从而可以获取ResponseEntity对象并获取HTTP状态码
背景
- 使用RestTemplate请求特定接口,并根据获取的HTTP状态码进行具体业务操作。
@RestController
public class RestfulController {
private RestTemplate restTemplate = new RestTemplate();
@GetMapping("/test1")
public void test1(HttpServletResponse response) {
response.setStatus(403);
}
@GetMapping("/test2")
public void test2() {
ResponseEntity responseEntity = restTemplate.exchange("http://127.0.0.1:8080/test1", HttpMethod.GET, new HttpEntity<String>(null, new HttpHeaders()), String.class);
int code = responseEntity.getStatusCodeValue();
// 具体业务操作...
}
}
报错
org.springframework.web.client.HttpClientErrorException$Forbidden: 403 null
解决
- 如果想要使用responseEntity.getStatusCodeValue()等,需要先为RestTemplate对象设置ResponseErrorHandler。
- 需要注意代码并不符合平常的开发规范,只是为了实现效果。
@RestController
public class RestfulController {
private RestTemplate restTemplate = new RestTemplate();
@GetMapping("/test1")
public void test1(HttpServletResponse response) {
response.setStatus(403);
}
@GetMapping("/test2")
public void test2() {
restTemplate.setErrorHandler(new RestfulController.ErrorHandler());
ResponseEntity responseEntity = restTemplate.exchange("http://127.0.0.1:8080/test1", HttpMethod.GET, new HttpEntity<String>(null, new HttpHeaders()), String.class);
int code = responseEntity.getStatusCodeValue();
// 业务处理...
}
static class ErrorHandler implements ResponseErrorHandler {
@Override
public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
if (200 == clientHttpResponse.getRawStatusCode()) {
return false;
}
return true;
}
@Override
public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
// 处理Error...
}
}
}
原因
- RestTemplate
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
...
private ResponseErrorHandler errorHandler;
...
public RestTemplate() {
...
// 默认的ResponseErrorHandler
this.errorHandler = new DefaultResponseErrorHandler();
...
}
...
@Nullable
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "URI is required");
Assert.notNull(method, "HttpMethod is required");
ClientHttpResponse response = null;
Object var14;
try {
ClientHttpRequest request = this.createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
// 处理Response, 这里如果抛出异常,就不会返回ResponseEntity对象
this.handleResponse(url, method, response);
var14 = responseExtractor != null ? responseExtractor.extractData(response) : null;
} catch (IOException var12) {
String resource = url.toString();
String query = url.getRawQuery();
resource = query != null ? resource.substring(0, resource.indexOf(63)) : resource;
throw new ResourceAccessException("I/O error on " + method.name() + " request for \"" + resource + "\": " + var12.getMessage(), var12);
} finally {
if (response != null) {
response.close();
}
}
return var14;
}
protected void handleResponse(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
ResponseErrorHandler errorHandler = this.getErrorHandler();
boolean hasError = errorHandler.hasError(response);
if (this.logger.isDebugEnabled()) {
try {
int code = response.getRawStatusCode();
HttpStatus status = HttpStatus.resolve(code);
this.logger.debug("Response " + (status != null ? status : code));
} catch (IOException var8) {
}
}
if (hasError) {
// 处理Http错误码
errorHandler.handleError(url, method, response);
}
}
...
}
- DefaultResponseErrorHandler
public class DefaultResponseErrorHandler implements ResponseErrorHandler {
public DefaultResponseErrorHandler() {
}
public boolean hasError(ClientHttpResponse response) throws IOException {
int rawStatusCode = response.getRawStatusCode();
HttpStatus statusCode = HttpStatus.resolve(rawStatusCode);
return statusCode != null ? this.hasError(statusCode) : this.hasError(rawStatusCode);
}
protected boolean hasError(HttpStatus statusCode) {
return statusCode.isError();
}
protected boolean hasError(int unknownStatusCode) {
Series series = Series.resolve(unknownStatusCode);
return series == Series.CLIENT_ERROR || series == Series.SERVER_ERROR;
}
public void handleError(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());
if (statusCode == null) {
throw new UnknownHttpStatusCodeException(response.getRawStatusCode(), response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
} else {
this.handleError(response, statusCode);
}
}
protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
String statusText = response.getStatusText();
HttpHeaders headers = response.getHeaders();
byte[] body = this.getResponseBody(response);
Charset charset = this.getCharset(response);
switch(statusCode.series()) {
case CLIENT_ERROR:
throw HttpClientErrorException.create(statusCode, statusText, headers, body, charset);
case SERVER_ERROR:
throw HttpServerErrorException.create(statusCode, statusText, headers, body, charset);
default:
throw new UnknownHttpStatusCodeException(statusCode.value(), statusText, headers, body, charset);
}
}
...
}
- RestTemplate中的getForEntity(…)、 getForObject(…)、exchange(…)和delete(…)等方法最终都是调用doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor responseExtractor)方法。
- 从源代码可以看出来默认的处理器DefaultResponseErrorHandler,最后会抛出三种异常:HttpClientErrorException、HttpServerErrorException、UnknownHttpStatusCodeException。所以在得到ResponseEntity返回值之前,就有异常抛出。
- 可以自定义错误处理器,自定义的处理器并没有抛出异常,所以也就可以返回ResponseEntity对象,并通过该对象的getStatusCodeValue()方法获取HTTP状态码。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
