Could not extract response: no suitable HttpMessageConverter found for content type [text/html]

这篇具有很好参考价值的文章主要介绍了Could not extract response: no suitable HttpMessageConverter found for content type [text/html]。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


如果是使用 OpenFeign 进行远程调用的时候,报以下错误 no suitable HttpMessageConverter

可考虑修改 feign 接口,如下,使用注解 @ResponseBody、@RequestBody

@FeignClient("gulimall-order")
public interface OrderFeignService {
    @RequestMapping("/order/order/listWithItem")
    @ResponseBody
    R listWithItem(@RequestBody Map<String, Object> params);
}

报错信息

在使用 RestTemplate请求调用的时候,程序报错

报错信息如下:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class afei.common.utils.R] and content type [text/html;charset=UTF-8]
	at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:121) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.cloud.openfeign.support.SpringDecoder.decode(SpringDecoder.java:59) ~[spring-cloud-openfeign-core-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at org.springframework.cloud.openfeign.support.ResponseEntityDecoder.decode(ResponseEntityDecoder.java:62) ~[spring-cloud-openfeign-core-2.1.3.RELEASE.jar:2.1.3.RELEASE]
	at feign.optionals.OptionalDecoder.decode(OptionalDecoder.java:36) ~[feign-core-10.2.3.jar:na]

错误信息是未知的ContentType,这个ContentType就是第三方接口返回时候在HTTP头中的Content-Type,如果通过其他工具查看这个接口返回的HTTP头,会发现他的值是 text/html,通常我们见的都是 application/json 类型。(微信接口返回的是text/plain),由于内部没有 HttpMessageConverter 能处理text/html的数据,没有一个实现类的 canRead() 返回 true,所以最后报错

Could not extract response: no suitable HttpMessageConverter found for content type [text/html]

源码分析

public T extractData(ClientHttpResponse response) throws IOException {
    MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);
    if (responseWrapper.hasMessageBody() && !responseWrapper.hasEmptyMessageBody()) {
        MediaType contentType = this.getContentType(responseWrapper);
        try {
        	//拿到messageConverters的迭代器
            Iterator var4 = this.messageConverters.iterator();
            while(var4.hasNext()) {
            	//下一个HttpMessageConverter
                HttpMessageConverter<?> messageConverter = (HttpMessageConverter)var4.next();
                //如果是GenericHttpMessageConverter接口的实例,继承AbstractHttpMessageConverter会走这个if。
                if (messageConverter instanceof GenericHttpMessageConverter) {
                    GenericHttpMessageConverter<?> genericMessageConverter = (GenericHttpMessageConverter)messageConverter;
                    //判断这个转换器能不能转换这个contentType类型
                    if (genericMessageConverter.canRead(this.responseType, (Class)null, contentType)) {
                        if (this.logger.isDebugEnabled()) {
                            ResolvableType resolvableType = ResolvableType.forType(this.responseType);
                            this.logger.debug("Reading to [" + resolvableType + "]");
                        }
                        //走到这代表当前的HttpMessageConverter能进行转换,则调用read并返回
                        return genericMessageConverter.read(this.responseType, (Class)null, responseWrapper);
                    }
                }
                //还是判断这个转换器能不能进行contentType转换
                if (this.responseClass != null && messageConverter.canRead(this.responseClass, contentType)) {
                    if (this.logger.isDebugEnabled()) {
                        String className = this.responseClass.getName();
                        this.logger.debug("Reading to [" + className + "] as \"" + contentType + "\"");
                    }
                    //走到这代表当前的HttpMessageConverter能进行转换,则调用read并返回
                    return messageConverter.read(this.responseClass, responseWrapper);
                }
            }
        } catch (HttpMessageNotReadableException | IOException var8) {
            throw new RestClientException("Error while extracting response for type [" + this.responseType + "] and content type [" + contentType + "]", var8);
        }
        //走到这抛出异常,所有的消息转换器都不能进行处理。
        throw new UnknownContentTypeException(this.responseType, contentType, response.getRawStatusCode(), response.getStatusText(), response.getHeaders(), getResponseBody(response));
    } else {
        return null;
    }
}

messageConverters 集合中就保存着
在 RestTemplate 构造方法中添加的 HttpMessageConverter 实现类

Could not extract response: no suitable HttpMessageConverter found for content type [text/html]

解决方法

修改 mappingJackson2HttpMessageConverter 配置

重新设置 MappingJackson2HttpMessageConverter 能处理的 MediaType

@Bean
public RestTemplate restTemplate(){
    RestTemplate restTemplate = new RestTemplate();
    MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
    mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_HTML));
    restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter);
    return  restTemplate;
}

MappingJackson2HttpMessageConverter 也是一个 HttpMessageConverter 转换类,但是他不能处理 text/html 的数据,原因是他的父类 AbstractHttpMessageConverter 中的 supportedMediaTypes 集合中没有 text/html 类型,如果有的话就能处理了,通过 setSupportedMediaTypes 可以给他指定一个新的 MediaType 集合

上面的写法会导致 MappingJackson2HttpMessageConverter 只能处理 text/html 类型的数据

继承 mappingJackson2HttpMessageConverter

使用MappingJackson2HttpMessageConverter,只需要给他能处理的MediaType

public class QQHttpMessageConverter extends MappingJackson2HttpMessageConverter {
    public QQHttpMessageConverter() {
        setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_HTML));
    }
}

然后将这个消息转换器追加到RestTemplate中的 messageConverters

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.getMessageConverters().add(new QQHttpMessageConverter());  // 兼容 text/plain
    return restTemplate;
}

实现 HttpMessageConverter

直接继承HttpMessageConverter(当然更推荐的是继承 Abstract HttpMessageConverter)来实现

public interface HttpMessageConverter<T> {
    /**
     * 根据mediaType判断clazz是否可读
     */
    boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

    /**
     * 根据mediaType判断clazz是否可写
     */
    boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

    /**
     * 获取支持的mediaType
     */
    List<MediaType> getSupportedMediaTypes();

    /**
     * 将HttpInputMessage流中的数据绑定到clazz中
     */
    T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException;

    /**
     * 将t对象写入到HttpOutputMessage流中
     */
    void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException;
}

canWrite,write方式是不需要处理的,只管canRead和read就行

在 canRead 方法中判断了是不是 text/html 类型,是的话就会返回true,Spring 就会调用 read,用来将字节流中的数据转换成具体实体,aClass就是我们最终想要得到的实例对象的Class

StreamUtils 这个工具类是SpringBoot自带的一个,用来读取InputStream中的数据并返回String字符串,SpringBoott内部很多地方都用到了这个工具类

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;

public class QQHttpMessageConverter implements HttpMessageConverter<Object> {
    @Override
    public boolean canRead(Class<?> aClass, MediaType mediaType) {
        if (mediaType != null) {
            return mediaType.isCompatibleWith(MediaType.TEXT_HTML);
        }
        return false;
    }

    @Override
    public boolean canWrite(Class<?> aClass, MediaType mediaType) {
        return false;
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return Arrays.asList(MediaType.TEXT_HTML);
    }

    @Override
    public Object read(Class<?> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        String json = StreamUtils.copyToString(httpInputMessage.getBody(), Charset.forName("UTF-8"));
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper.readValue(json, aClass);
    }

    @Override
    public void write(Object o, MediaType mediaType, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {

    }
}

最后需要要进行配置,getMessageConverters() 会返回现有的 HttpMessageConverter 集合,我们在这个基础上加入我们自定义的 HttpMessageConverter 即可文章来源地址https://www.toymoban.com/news/detail-477165.html

@Bean
public RestTemplate restTemplate(){
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.getMessageConverters().add(new QQHttpMessageConverter());
    return  restTemplate;
}

继承 AbstractHttpMessageConverter

public class QQHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
    public QQHttpMessageConverter() {
        super(MediaType.TEXT_HTML);
    }
    @Override
    protected boolean supports(Class<?> aClass) {
        return true;
    }
    @Override
    protected Object readInternal(Class<?> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        String json = StreamUtils.copyToString(httpInputMessage.getBody(), Charset.forName("UTF-8"));
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper.readValue(json, aClass);
    }
    @Override
    protected void writeInternal(Object o, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
    }
}

到了这里,关于Could not extract response: no suitable HttpMessageConverter found for content type [text/html]的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 互联网大厂技术-HTTP请求-Springboot整合Feign更优雅地实现Http服务调用 no suitable HttpMessageConverter found for response type

    目录 一、SpringBoot快速整合Feign 1.添加Pom依赖 2.启动类添加注解 3.引用Feign服务 二、为请求添加Header的3种方式 1.添加固定header 2.通过接口签名添加header 3.动态添加header 三、为请求添加超时配置 1.默认超时时间 3.超时异常 4.全局超时配置 5.为单个服务设置超时配置 四、为请求配

    2024年02月11日
    浏览(55)
  • Could not autowire. No beans of ‘DiscoveryClient‘ type found.

    一、导错了包 DiscoveryClient对应有两个包: org.springframework.cloud.client.discovery.DiscoveryClient; com.netflix.discovery.DiscoveryClient; 目前导入的包是: 改成第一个包,发现不再报红了。

    2024年02月11日
    浏览(43)
  • idea报错:Could not autowire. No beans of ‘UserService‘ type found.

    点个关注,必回关 翻译:无法自动连线。未找到“用户服务”类型的服务类。 当报错之后idea会提示错误,不过程序的编译和运行都是没有问题的(这个错误提示不会产生任何印象) 解决方案 解决方案1: Settings - Editor - Inspections - Spring - Spring Core - Code - Autowiring for Bean Class

    2024年02月11日
    浏览(49)
  • @Autowired报错Could not autowire. No beans of ‘XXX‘ type found

      IDEA中使用 @Autowired 报错 Could not autowire. No beans of \\\'XXX\\\' type found ,错误大致意思为:没有匹配到类型为XXX的bean。   个人觉得,注入 controller 的 service 虽然一般来说我们都是注入一个接口,但是该接口有实现类,并且使用 @Service 进行关联,所以注入类型应该也可以视为一

    2024年02月07日
    浏览(48)
  • idea报“Could not autowire. No beans of ‘UserMapper‘ type found. ”错解决办法

    idea具有检测功能,接口不能直接创建bean的,需要用动态代理技术来解决。 1.修改idea的配置 1.点击file,选择setting 2.搜索inspections,找到Spring 3.找到Spring子目录下的Springcore 4.在Springcore的子目录下找到code 5.把seyerity选项改成警告 2.修改代码 1,@Autowrited改为@Autowrited(required = false)

    2024年02月05日
    浏览(67)
  • IDEA提示找不到Mapper接口:Could not autowire.No beans of ‘xxxMapper‘ type found

    我们可以看到,上面的红色警告在提示我们,找不到 xxxMaper 这个类型的 bean。 为啥呢? 因为 @Mapper 这个注解是 Mybatis 提供的,而 @Autowried 注解是 Spring 提供的,IDEA能理解 Spring 的上下文,但是却和 Mybatis 关联不上。而且我们可以根据 @Autowried 源码看到,默认情况下,@Autowri

    2024年02月08日
    浏览(43)
  • 解决SpringBoot项目中的报错:Could not autowire,no beans of “XXX“ type found

    问题:找不到mapper注入的bean,如图   分析:注入mapper有两种方式:  第一种:在启动类中添加  @MapperScan        然后在mapper的类中添加  @Repository 注解 第二种方法:直接在各个mapper类中添加@Mapper注解,但是一定要注意导入正确的包,否则解决不了这个异常;  很多新手

    2024年02月08日
    浏览(52)
  • SpringBoot - 在IDEA中经常发现:Could not autowire. No beans of ‘xxx‘ type found的错误

    错误描述 在SPRINGBOOT的项目中,使用IDEA时经常会遇到Could not autowire. No beans of ‘xxxx’ type found的错误提示,但是程序的编译和运行都没有问题,这个错误提示并不影响项目的生产。 解决方案

    2024年02月15日
    浏览(53)
  • Qt创建控制台程序选择构建套件问题“No suitable kits found”

    QT 选择构建套件时出现问题: “No suitable kits found” = 没有找到合适的kits套件,在安装Qt Creator时没有安装MinGW,所以只需要进行安装即可。 3.1 选择安装目录下的“MaintenanceTool.exe”,双击计入组件安装界面。 3.2 点击“下一步” 3.3 选择“添加或移除组件”: 3.4 根据自己安装

    2024年02月11日
    浏览(41)
  • 已解决No suitable driver found for jdbc:mysql://localhost:3306/ 问题

    已解决No suitable driver found for jdbc:mysql://localhost:3306/ 问题 在学习java数据库连接池使用的时候遇到问题,无法连接到数据库,查看日志是\\\"No Suitable Driver Found For Jdbc\\\",但查看数据库连接配置没问题。 这个问题可把我愁坏了,要不问一下GPT?上。 问了一下GPT,得到的答案是这样的

    2024年02月07日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包