问题
今天在对接第三方接口的时候,发现通过restTemplate post请求提交过去的中文数据会乱码。
排查
首先,我方的编码全部使用utf8。请求第三方获取数据的接口,发现刚刚提交的数据是乱码,而更早提交的几条数据则正常。因此基本可以排除对方的问题,和response的问题。
于是,问题大概率在restTemplate发送请求的时候编码格式不正确。
根据返回的乱码数据,用vscode基本可以推测对方系统编码是GBK(后来沟通后确实是GBK)
然后,使用网上见得最多的方法:
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
messageConverters.set(1, new StringHttpMessageConverter(Charset.forName("GBK")));
乱码还是存在。
继续debug,跟踪到RestTemplate.class中的doWithRequest方法后,发现问题所在:
public void doWithRequest(ClientHttpRequest httpRequest) throws IOException {
......
......
messageConverter.write(requestBody, requestContentType, httpRequest);
......
}
这里把requestBody写入的时候,用的messageConverter是AllEncompassingFormHttpMessageConverter,而此时它的默认编码是utf8。刚才去修改StringHttpMessageConverter是牛头不对马嘴。
(这里粗心了,我明明是用MultiValueMap传参的,为什么要去改StringHttpMessageConverter呢。。。)
解决
到这里,问题就已经解决了:
// 处理请求中文乱码问题
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter instanceof AllEncompassingFormHttpMessageConverter) {
((AllEncompassingFormHttpMessageConverter) messageConverter).setCharset(thirdRequest);
}
}
获取restTemplate的代码:
/**
* 第三方请求要求的默认编码
*/
private final Charset thirdRequest = Charset.forName("GBK");
/**
* 第三方RestTemplate
*
* @return
*/
@Bean(name = "thirdRestTemplate")
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
// 处理请求中文乱码问题
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) messageConverter).setDefaultCharset(thirdRequest);
}
if (messageConverter instanceof MappingJackson2HttpMessageConverter) {
((MappingJackson2HttpMessageConverter) messageConverter).setDefaultCharset(thirdRequest);
}
if (messageConverter instanceof AllEncompassingFormHttpMessageConverter) {
((AllEncompassingFormHttpMessageConverter) messageConverter).setCharset(thirdRequest);
}
}
return restTemplate;
}