相关文章推荐
有胆有识的斑马  ·  REST Clients :: ...·  2 周前    · 
首页 > 软件编程 > java > RestTemplate报错RestClientException

解决使用RestTemplate时报错RestClientException的问题

作者:墨一般的白色

这篇文章主要介绍了解决使用RestTemplate时报错RestClientException的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

使用RestTemplate时报错RestClientException

这是自己封装的一个发送请求的方法

public Map<String, Object> sendRequest(Map<String, Object> body,String sessionId,String url) { RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(new BdMappingJackson2HttpMessageConverter()); Map<String, Object> map = new HashMap<>(); try { ParameterizedTypeReference<Map<String, Object>> typeRef = new ParameterizedTypeReference<Map<String, Object>>() { 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 = restTemplate.exchange(url, HttpMethod.POST, requestEntity,typeRef); map = responseEntity.getBody(); log.info(map.toString()); } catch (HttpStatusCodeException e) { log.error(e.getResponseBodyAsString(), e); map = JsonUtil.toMap(e.getResponseBodyAsString()); 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 = this.getHttpStatusCode(response); switch(null.$SwitchMap$org$springframework$http$HttpStatus$Series[statusCode.series().ordinal()]) { case 1: throw new HttpClientErrorException(statusCode, response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response)); case 2: throw new HttpServerErrorException(statusCode, response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response)); default: throw new RestClientException("Unknown status code [" + statusCode + "]");

    可见,4xx的状态吗会抛出HttpClientErrorException;5xx的状态码会抛出HttpServerErrorException。这也就是我们一开始遇到的问题的原因所在了。而在handleError中,执行了response.getBody(),这就导致我们后续获取不到响应体了,如果要获取的话,需要进行自定义相关处理。

    如果RestTemplate的应用场景比较统一,可以自定义ResponseErorHandler(派生自DefaultResponseErrorHandler)来接管错误处理,进行自己想要的处理。

    而我们的网关中,对于页面跳转类的请求和Rest API类的请求,处理办法显然是不一样的。所以最终处理是catch异常,然后进行重定向的处理操作。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

    您可能感兴趣的文章:
  • Java9新特性对HTTP2协议支持与非阻塞HTTP API
    Java9新特性对HTTP2协议支持与非阻塞HTTP API
    2022-03-03
  • Java使用bcrypt实现对密码加密效果详解
    Java使用bcrypt实现对密码加密效果详解
    2022-03-03
  • Java的内存区域与内存溢出异常你了解吗
    Java的内存区域与内存溢出异常你了解吗
    2022-03-03
  • java理论基础Stream管道流状态与并行操作
    java理论基础Stream管道流状态与并行操作
    2022-03-03
  • RestTemplate自定义请求失败异常处理示例解析
    RestTemplate自定义请求失败异常处理示例解析
    2022-03-03
  • OpenFeign在传递参数为对象类型是为空的问题
    OpenFeign在传递参数为对象类型是为空的问题
    2022-03-03
  • 基于Feign传输对象无法接收参数的问题
    基于Feign传输对象无法接收参数的问题
    2022-03-03
  • RestTemplate的DELETE及PUT等请求方法使用精讲
    RestTemplate的DELETE及PUT等请求方法使用精讲
    2022-03-03
  • 美国设下计谋,用娘炮文化重塑日本,已影响至中国
    美国设下计谋,用娘炮文化重塑日本,已影响至中国
    2021-11-19
  • 时空伴随者是什么意思?时空伴随者介绍
    时空伴随者是什么意思?时空伴随者介绍
    2021-11-09
  • 工信部称网盘企业免费用户最低速率应满足基本下载需求,天翼云盘回应:坚决支持,始终
    工信部称网盘企业免费用户最低速率应满足基本下载需求,天翼云盘回应:坚决支持,始终
    2021-11-05
  • 2022年放假安排出炉:五一连休5天 2022年所有节日一览表
    2022年放假安排出炉:五一连休5天 2022年所有节日一览表
    2021-10-26
  • 电脑版 - 返回首页

    2006-2023 脚本之家 JB51.Net , All Rights Reserved.
    苏ICP备14036222号