在使用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;
    }

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐