RestTemplate中文乱码Response问号
背景描述
需要请求内部restful接口,那么有以下两种方式可以选择
- httpclient封装请求
- 优点 最底层的实现方式,很直观的能看到整个过程是如何实现的,也方便调优,调参数等等操作简单明了。
- 缺点 代码繁琐,大段大段的实现,而且互相之间封装的方式又千奇百怪。
- RestTemplate调用接口
- 优点 经过模板模式封装以后提供了简洁明了的设计和通用的模板方法进行调用,基本可以满足绝大多数要求,代码优美明了,耦合度大幅度降低。
- 缺点 学习成本相对方式一较大,封装程度高难以调试和发现问题,容易扩展但是需要很了解整个包如何使用。
问题现象
发送POST请求,参数有中文有英文,返回的结果看起来除了中文乱码是正常的。其中请求方法使用了模板方法的postForObject
,直接返回字符串。中文乱码表现为???
。
简单的分析
- 出现问号的乱码看起来并不是GBK UTF-8这种类型的编码问题,否则会出现一堆奇怪的
昆金卡考烫
什么的而不是???
。 - 请求其他人的接口返回中文正常请求这个接口返回乱码,说明可能原因有一部分在接口部分。
谷歌百度了一天,大部分人都说的是StringHttpMessageConverter
的原因,RestTemplate会我们默认注册一系列Converter,其中包括一个StringHttpMessageConverter
,详细的可以用搜索引擎搜索相关。他的默认编码确实是ISO-8859-1,这是spring-web写死在代码中的默认值,但是修改了该值并不见效,返回结果没有发生一点变化,而且也和分析1中的判断有出入。翻阅一些人的文章和文档后发现,StringHttpMessageConverter
本质上是一个转换请求的处理器,他是用来解决服务端接收到中文乱码现象的解决方式,另外有处理器用来处理返回后的数据来转换成文本或者实体,比如MappingJackson2HttpMessageConverter
。RestTemplate提供很多处理器来处理返回文本的不同格式,比如text/html text/json text/plain,正合了上述分析2中的第二点,有的人接口默认返回的格式刚好和MappingJackson2HttpMessageConverter
默认解析的格式一样。
解决方式
上代码
@Configuration
public class BeanConfig {
@Bean(value = "rest")
public RestTemplate getRestTemplateBuilder(){
RestTemplate restTemplate = new RestTemplateBuilder()
.setConnectTimeout(1000)
.setReadTimeout(1000)
.build();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
stringHttpMessageConverter.setWriteAcceptCharset(true);
List<MediaType> mediaTypeList = new ArrayList<>();
mediaTypeList.add(MediaType.ALL);
for (int i = 0; i < restTemplate.getMessageConverters().size(); i++) {
if (restTemplate.getMessageConverters().get(i) instanceof StringHttpMessageConverter) {
restTemplate.getMessageConverters().remove(i);
restTemplate.getMessageConverters().add(i, stringHttpMessageConverter);
}
if(restTemplate.getMessageConverters().get(i) instanceof MappingJackson2HttpMessageConverter){
try{
((MappingJackson2HttpMessageConverter) restTemplate.getMessageConverters().get(i)).setSupportedMediaTypes(mediaTypeList);
}catch(Exception e){
e.printStackTrace();
}
}
}
return restTemplate;
}
}
重点在于第一个处理器加上了修改了默认编码,第二个处理添加了mediaTypeList.add(MediaType.ALL);
解析所有返回数据的格式。
本次的问题有别于网上所有跟这个问题相关的答案,但是真的花了我大半天的时间。主要还是对RestTemplate不熟悉的缘故。
网友评论