解决 RestTemplate 报错 UnknownContentTypeException


之前项目都是使用 HttpClient 进行 api 调用,代码较为复杂。新项目正好想试试 spring 自家封装的 RestTemplate,没想到第一个小程序服务端获取 openid 的请求直接就翻车了,异常如下:

org.springframework.web.client.UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [class ***] and content type [text/plain]

debug 发现响应内容正常,出错的原因是微信这个坑货 响应头中的 Content-Type 是 text/plain。

解决方法有两种,如下:

使用 String 类型接收

String res = restTemplate.getForObject(url,String.class,map);
// 使用json转换工具将String类型的数据转换为对象

这个方法简单有效,但是每个 api 调用的地方都这么写下感觉挺丑的

自定义 HttpMessageConverter

研究源码发现 RestTemplate 在静态代码块和无参构造中通过类加载器判断,初始化对应的消息转换器

// RestTemplate部分源码
public RestTemplate() {
    this.messageConverters.add(new ByteArrayHttpMessageConverter());
    this.messageConverters.add(new StringHttpMessageConverter());
    this.messageConverters.add(new ResourceHttpMessageConverter(false));
    if (jackson2Present) {
        this.messageConverters.add(new MappingJackson2HttpMessageConverter());
    }
    else if (gsonPresent) {
        this.messageConverters.add(new GsonHttpMessageConverter());
    }
    else if (jsonbPresent) {
        this.messageConverters.add(new JsonbHttpMessageConverter());
    }
    //...
}

我的项目中使用 jackson 作为 json 序列化工具,所以直接继承 MappingJackson2HttpMessageConverter 这个实现就好了。如果你使用其他的 json 序列化工具,就根据源码自行修改

// CustomJacksonHttpMessageConverter.java
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.util.Collections;

public class CustomJacksonHttpMessageConverter extends MappingJackson2HttpMessageConverter {
    public CustomJacksonHttpMessageConverter() {
        this(Jackson2ObjectMapperBuilder.json().build());
    }

    public CustomJacksonHttpMessageConverter(ObjectMapper objectMapper) {
        super(objectMapper);
        // 这里是重点,增加支持的类型,看你的情况加
        // 我这里目前只需要加个 TEXT/PLAIN
        setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN,
                MediaType.APPLICATION_JSON,
                new MediaType("application", "*+json")));
    }
}

最后修改下 RestTemplate 的配置,将自定义的消息转换器和原来的替换

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;


@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate() {
        // 创建 RestTemplate 实例, 我这里使用的OkHttp
        RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());
        // 替换默认的 Jackson 消息转换器实现
        List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        Iterator<HttpMessageConverter<?>> iterator = messageConverters.iterator();
        while (iterator.hasNext()) {
            HttpMessageConverter<?> next = iterator.next();
            if (next instanceof MappingJackson2HttpMessageConverter) {
                iterator.remove();
                break;
            }
        }
        messageConverters.add(new CustomJacksonHttpMessageConverter());
        return restTemplate;
    }
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM