解决使⽤RestTemplate时报错RestClientException的问题⽬录
使⽤RestTemplate时报错RestClientException
这是⾃⼰封装的⼀个发送请求的⽅法
这是⾃定义的⼀个http信息Converter
RestTemplate的错误处理
问题描述
ErrorHandler
解决办法
使⽤RestTemplate时报错RestClientException
这是⾃⼰封装的⼀个发送请求的⽅法
public Map<String, Object> sendRequest(Map<String, Object> body,String sessionId,String url) {
RestTemplate restTemplate = new RestTemplate();
Map<String, Object> map = new HashMap<>();
try {
ParameterizedTypeReference<Map<String, Object>> typeRef = new ParameterizedTypeReference<Map<String, Object>>() {
};
springframework是什么意思HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.set("cookie", "SESSION="+sessionId);
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(body,headers);
ResponseEntity<Map<String, Object>> responseEntity = hange(url, HttpMethod.POST,
requestEntity,typeRef);
map = Body();
log.String());
} catch (HttpStatusCodeException e) {
<(e.getResponseBodyAsString(), e);
map = ResponseBodyAsString());
}
return map;
}
这是⾃定义的⼀个http信息Converter
public class BdMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
public BdMappingJackson2HttpMessageConverter(){
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.TEXT_HTML);
mediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
setSupportedMediaTypes(mediaTypes);
}
}
我遇到的第⼀个问题是这样的
Could not write request: no suitable HttpMessageConverter found for request type [java.util.HashMap] and content type [application/octet-stream]
意思⼤概是⽆法写⼊请求:不到适⽤于请求类型[java.util.HashMap]和内容类型[application/octet stream]的HttpMessageConverter 它默认只处理application/json:JSON数据格式,这个⼆进制数据流格式不⽀持,所以我在那个⾃定义的Converter加上去了。
紧接着⼜遇到第⼆个问题
Could not extract response: no suitable HttpMessageConverter found for response type [java.util.Map<java.lang.String, java.lang.Object>] and content type [text/xml;charset=UTF-8]
⽆法提取响应:不到适合于响应类型[java.util.Map<java.lang.String,java.lang.Object>]和内容类型[textml/charset=UTF-8]的HttpMessageConverter
这是那边回调过来的Content-Type类型是text/xml它同样解析不了,所以我把这个也加上去了,⾄此就ok了。
常见的Content-Type类型:
text/html:HTML格式
text/plain:纯⽂本格式
image/png:png图⽚格式
application/json:JSON数据格式
application/octet-stream:⼆进制流数据
application/x-www-form-urlencoded:表单中默认的encType,表单数据被编码为key/value格式发送到服务器
multipart/form-data:需要在表单中进⾏⽂件上传时,就需要使⽤该格式
RestTemplate的错误处理
我们的项⽬属于微服务架构,两个基础的服务分别是⽹关和认证鉴权服务。
在前端访问后台服务的时候,都经过⽹关转发,转发之前会进⾏鉴权认证,根据鉴权结果判断是否可以进⾏相应的请求转发。
问题描述
认证鉴权服务中,判断Token对应的⼈员是否有相应的权限,如果没有权限,返回401状态码并在响应体
中传回错误信息。
⽹关与鉴权服务之间的服务调⽤通过RestTemplate进⾏(可以考虑转为Feign做声明式的服务调⽤),然⽽如果鉴权服务返回401的情况
下,⽹关服务直接报出HttpClientErrorException,让⼈⼀头雾⽔。
实际上,答案都在源码中,看⼀下RestTemplate的源码就知晓了。
ErrorHandler
在RestTemplate中,有⼀个成员变量ResponseErrorHandler。
ResponseErrorHandler是⼀个接⼝,包括两个⽅法:
public interface ResponseErrorHandler {
boolean hasError(ClientHttpResponse var1) throws IOException;
void handleError(ClientHttpResponse var1) throws IOException;
}
这个接⼝有⼀个默认实现DefaultResponseErrorHandler。该⽅法中,判断是否发⽣error的⽅法hasError最终调⽤的⽅法如下:
protected boolean hasError(HttpStatus statusCode) {
return statusCode.series() == Series.CLIENT_ERROR || statusCode.series() == Series.SERVER_ERROR;
}
很明显,根据响应状态吗为4xx或者5xx来认定发⽣了错误。⽽错误处理在handleError中:
public void handleError(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = HttpStatusCode(response);
switch(null.$SwitchMap$org$springframework$http$HttpStatus$Series[statusCode.series().ordinal()]) {
case 1:
throw new HttpClientErrorException(statusCode, StatusText(), Headers(), thi
throw new HttpServerErrorException(statusCode, StatusText(), Headers(), ResponseBody(response), Charset(response)); default:
throw new RestClientException("Unknown status code [" + statusCode + "]");
}
}
可见,4xx的状态吗会抛出HttpClientErrorException;5xx的状态码会抛出HttpServerErrorException。这也就是我们⼀开始遇到的问题的原因所在了。⽽在handleError中,执⾏了Body(),这就导致我们后续获取不到响应体了,如果要获取的话,需要进⾏⾃定义相关处理。
解决办法
如果RestTemplate的应⽤场景⽐较统⼀,可以⾃定义ResponseErorHandler(派⽣⾃DefaultResponseErrorHandler)来接管错误处理,进⾏⾃⼰想要的处理。
⽽我们的⽹关中,对于页⾯跳转类的请求和Rest API类的请求,处理办法显然是不⼀样的。所以最终处理是catch异常,然后进⾏重定向的
处理操作。
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论