RestTemplate中文亂碼Response問號
背景描述
需要請求內部restful接口,那么有以下兩種方式可以選擇
- httpclient封裝請求
- 優(yōu)點 最底層的實現方式,很直觀的能看到整個過程是如何實現的,也方便調優(yōu),調參數等等操作簡單明了。
- 缺點 代碼繁瑣,大段大段的實現,而且互相之間封裝的方式又千奇百怪。
- RestTemplate調用接口
- 優(yōu)點 經過模板模式封裝以后提供了簡潔明了的設計和通用的模板方法進行調用,基本可以滿足絕大多數要求,代碼優(yōu)美明了,耦合度大幅度降低。
- 缺點 學習成本相對方式一較大,封裝程度高難以調試和發(fā)現問題,容易擴展但是需要很了解整個包如何使用。
問題現象
發(fā)送POST請求,參數有中文有英文,返回的結果看起來除了中文亂碼是正常的。其中請求方法使用了模板方法的postForObject,直接返回字符串。中文亂碼表現為???。
簡單的分析
- 出現問號的亂碼看起來并不是GBK UTF-8這種類型的編碼問題,否則會出現一堆奇怪的
昆金卡考燙什么的而不是???。 - 請求其他人的接口返回中文正常請求這個接口返回亂碼,說明可能原因有一部分在接口部分。
谷歌百度了一天,大部分人都說的是StringHttpMessageConverter的原因,RestTemplate會我們默認注冊一系列Converter,其中包括一個StringHttpMessageConverter,詳細的可以用搜索引擎搜索相關。他的默認編碼確實是ISO-8859-1,這是spring-web寫死在代碼中的默認值,但是修改了該值并不見效,返回結果沒有發(fā)生一點變化,而且也和分析1中的判斷有出入。翻閱一些人的文章和文檔后發(fā)現,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不熟悉的緣故。