使⽤RestTemplate请求,接⼝返回400+或500+不抛出异常的
⽅法
使⽤RestTemplate请求其他服务的时候,经常会遇到返回401,404,400,或者由于业务逻辑报500等情况,这种时候RestTemplate 会报异常RestClientException,所以代码⾥⾯就必须catch异常再继续⾛逻辑,⾮常⿇烦。
这种情况多了就想让他不报错,因为返回的ResponseEntity中已经有了返回码,返回头和返回体的全部信息,可以⾃⼰处理这些信息。下⾯开始介绍解决办法。
从RestTemplate的请求⽅法⼊⼿,⾛查代码exchange→execute→doExecute,发现返回值在请求后,会通过handleResponse()判断是否有错误,判断和处理交由ResponseErrorHandler对象处理异常。
现在思路就清晰了,只要将restTemplate的ResponseErrorHandler定制⼀下就可以。
解决了基本问题后⼜发现⼀个问题。由于我们的返回信息在正常情况和异常情况下结构是不同的,即RestTemplate<T>中的T可能会变成其他结构,甚⾄⼀个errorMsg,这时候需要特殊处理。继续看代码,在handleResponse()之后,response交由⼀个ResponseExtractor<T> 负责抽取信息,查看该接⼝的实现,由于需要返回ResponseEntity,到内部实现类ResponseEntityResponseExtractor,发现该类是Ht
tpMessageConverterExtractor的⼀个代理类,这个被代理的抽取器进⼊extractData⽅法。⽅法⾥主要就是从默认的HttpMessageConverter中挑选⼀个,然后对返回的数据流进⾏解析。
我们的问题是已经声明了泛型为我们需要的类型,那message这种字符串怎么放呢?这⾥我暂时的办法是就放到body中,因为我也不知道放哪好。由于我们声明了泛型,就不能简单的放到body⾥了,因为我们知道的泛型并不是真正的类型,只是引⽤类型的编译和擦除实现,所以就通过强转、擦除的⽅式将⽆法转换的body直接以字符串形式放到body中。
具体代码:
public class NoErrorResultErrorHandler extends DefaultResponseErrorHandler {
@Override
public void handleError(ClientHttpResponse response) {
}
}
2.⾃定义返回的ResponseEntity,擦除返回值类型
public class EraseTypeResponseEntity extends ResponseEntity {
private String msg;
EraseTypeResponseEntity(String msg, MultiValueMap<String, String> headers, HttpStatus status) {
super(null, headers, status);
this.msg = msg;
}
@Override
public Object getBody() {
return this.msg;
}
}
3.⾃定义数据抽取器,如果body正常解析不成功,就使⽤⾃定义的返回Entity,把返回值直接以String形式放到body中
public class NoExceptionRestTemplateResponseEntityExtractor<T> implements ResponseExtractor<ResponseEntity<T>> {
private static final Logger log = Logger(NoExceptionRestTemplateResponseEntityExtractor.class);
private final HttpMessageConverterExtractor<T> delegate;
NoExceptionRestTemplateResponseEntityExtractor(Type responseType, List<HttpMessageConverter<?>> converters) {
if (responseType != null && Void.class != responseType) {
this.delegate = new HttpMessageConverterExtractor<>(responseType, converters);
} else {
this.delegate = null;
}
}
@Override
public ResponseEntity<T> extractData(ClientHttpResponse response) throws IOException {
if (this.delegate != null) {
T body = null;
try {
body = actData(response);
} catch (RuntimeException e) {
String content;
try {
content = Body(), UTF_8);
<("请求接⼝时返回[" + content + "],⽆法解析返回值", e);
} catch (Exception exception) {
content = "";
<("请求接⼝时返回未知结果,⽆法解析返回值", exception);
}
return new EraseTypeResponseEntity(content, Headers(), StatusCode());
}
return new ResponseEntity<>(body, Headers(), StatusCode());
} else {
return new ResponseEntity<>(Headers(), StatusCode());
}
}
}
4. 创建RestTemplate代理,使⽤⾃定义的收据抽取器
public class RestTemplateProxy extends RestTemplate {
@Override
protected <T> ResponseExtractor<ResponseEntity<T>> responseEntityExtractor(Type responseType) {
return new NoExceptionRestTemplateResponseEntityExtractor<>(responseType, getMessageConverters());
}
@Override
protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor) throws RestClientException {
logger.info("发起请求" + String() + " " + String());
T t = super.doExecute(url, method, requestCallback, responseExtractor);
logger.info("请求" + String() + " " + String() + "返回:" + BeanToStringUtil.stringBean(t));
return t;
}
}
5. 使⽤⾃定义的代理取代默认注⼊的RestTemplate
@Bean
public RestTemplate restTemplate(ObjectMapper objectMapper) {
try catch的使用方法RestTemplate restTemplate = new RestTemplateProxy();
restTemplate.setErrorHandler(new NoErrorResultErrorHandler());
return restTemplate;
}
6.使⽤的时候不需要再try-catch,可以通过返回值判断接⼝数据是否正常,例如:
HttpEntity requestEntity = new CloudIp())); ResponseEntity<ActionPageWrapperDTO> responseEntity = hange(builder.build(),
HttpMethod.GET,
requestEntity,
ActionPageWrapperDTO.class,
if (HttpStatus.OK == StatusCode()) {
Body();
} else if (HttpStatus.NOT_FOUND == StatusCode()) {
ActionPageWrapperDTO response = new ActionPageWrapperDTO();
response.wArrayList());
response.setTotal(0);
response.setPageSize(pageSize);
response.setPageNo(pageNo);
return response;
} else {
<("查询伸缩事件列表SERV-异常-actionId:{},param:{},返回结果:[{}]", actionId, BeanToStringUtil.stringBean(certainGroupIdBO), BeanToStringUtil.stringBean(responseEntity));
throw new ActionNetworkException("查询伸缩事件列表异常");
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。