在使用restTemplate请求restful接口时,在特定情况下总会将返回的json数据解析为xml数据然后处理,接着就会爆出标题中的错误:
Error while extracting response for type [] and content type [application/xml;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character '5' (code 53) in content after '<' (malformed start element?).
at [row,col {unknown-source}]: [1,15395]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unexpected character '5' (code 53) in content after '<' (malformed start element?).
根据错误信息来看,似乎响应头标记了返回类型为[application/xml;charset=UTF-8],然而实际情况是所有的返回数据都是[application/json;charset=UTF-8]。
跟踪restTemplate源码,发现由new RestTemplate(httpRequestFactory())创建的实例会有7个converter:
继续跟踪restTemplate的exchange,当对response进行类型转换时,会迭代当前实例中所有的converter,然后选择一个支持当前类型的converter执行,使用canRead来判断:
此时就发现了问题,在特定情况下,响应头的contentType被读作了"application/xml",然而此时的真实数据仍然为json格式。所以将用于xml格式的converter删除,则迭代器会寻找下一个可执行的converter即MappingJackson2HttpMessageConverter。或者将二者顺序换一下,降低xml的优先级。
解决办法:
方案1:删除xml的转换器
@Bean
public RestTemplate restTemplate() {
RestTemplate template = new RestTemplate(httpRequestFactory());
// 排除掉xml的解析converter,避免将json数据当做xml解析
List<HttpMessageConverter<?>> collect = template.getMessageConverters().stream()
.filter(m -> !(m instanceof MappingJackson2XmlHttpMessageConverter))
.collect(Collectors.toList());
template.setMessageConverters(collect);
return template;
}
方案2:降低xml转换器优先级
@Bean
public RestTemplate restTemplate() {
RestTemplate template = new RestTemplate(httpRequestFactory());
// 将xml解析的优先级调低
int xml = 0, json = 0;
List<HttpMessageConverter<?>> messageConverters = template.getMessageConverters();
for (int i = 0; i < messageConverters.size(); i++) {
HttpMessageConverter<?> h = messageConverters.get(i);
if (h instanceof MappingJackson2XmlHttpMessageConverter) {
xml = i;
} else if (h instanceof MappingJackson2HttpMessageConverter) {
json = i;
}
}
Collections.swap(template.getMessageConverters(), xml, json);
return template;
}