在一次工作中,使用Springboot的RestTemplate请求接口时,出现了以下报错信息:
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class java.lang.Object] and content type [text/plain;charset=UTF-8]
大概意思就是说:当前RestTemplate中的HttpMessageConverter转换器无法处理text/plain;charset=UTF-8
类型,导致的结果就是RestTemplate将数据从HttpResponse转换成Object的时候,找不到合适的HttpMessageConverter
进行转换!
问题查找
通过查看RestTemplate
类源码,我们可以看到:
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations {
private static final boolean romePresent;
private static final boolean jaxb2Present;
private static final boolean jackson2Present;
private static final boolean jackson2XmlPresent;
private static final boolean jackson2SmilePresent;
private static final boolean jackson2CborPresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
private final List<HttpMessageConverter<?>> messageConverters;
private ResponseErrorHandler errorHandler;
private UriTemplateHandler uriTemplateHandler;
private final ResponseExtractor<HttpHeaders> headersExtractor;
public RestTemplate() {
this.messageConverters = new ArrayList();
this.errorHandler = new DefaultResponseErrorHandler();
this.headersExtractor = new HeadersExtractor();
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
} else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter()); // application/json
} else if (gsonPresent) {
this.messageConverters.add(new GsonHttpMessageConverter());
} else if (jsonbPresent) {
this.messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
}
if (jackson2CborPresent) {
this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
}
this.uriTemplateHandler = initUriTemplateHandler();
}
public RestTemplate(List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = new ArrayList();
this.errorHandler = new DefaultResponseErrorHandler();
this.headersExtractor = new HeadersExtractor();
Assert.notEmpty(messageConverters, "At least one HttpMessageConverter required");
this.messageConverters.addAll(messageConverters);
this.uriTemplateHandler = initUriTemplateHandler();
}
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
Assert.notEmpty(messageConverters, "At least one HttpMessageConverter required");
if (this.messageConverters != messageConverters) {
this.messageConverters.clear();
this.messageConverters.addAll(messageConverters);
}
}
public List<HttpMessageConverter<?>> getMessageConverters() {
return this.messageConverters;
}
}
构造函数中包含了多种messageConverters消息转换器,其中RestTemplate使用MappingJackson2HttpMessageConverter
默认处理application/json
类型,但是我们发现确实没有其他的messageConverters支持处理text/plain
,这样就会导致上述报错。
既然问题找到了,那么解决办法也很简单,就是再增加一个messageConverters
,专门用于转换处理text/plain
类型
解决
我们选择兼容的方式,而不是替换RestTemplate默认的消息转换器,即新建一个类,继承MappingJackson2HttpMessageConverter
,如下:
/**
* @date 2022-12-4
* @desc 兼容处理 Content-Type 为 text/plain 类型的json返回值
*/
public class HsMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
public HsMappingJackson2HttpMessageConverter() {
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.TEXT_PLAIN);
setSupportedMediaTypes(mediaTypes);
}
}
然后将这个消息转换器追加到RestTemplate中的 messageConverters
即可,如下:
// 添加到 Springboot 的启动类中即可
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new HsMappingJackson2HttpMessageConverter()); // 兼容 text/plain
return restTemplate;
}
最后通过依赖注入的方式就可以正常处理,接口请求头中Content-Type
为text/plain;charset=UTF-8
的接口啦
@Resource
private final RestTemplate restTemplate;