首页 > 基础资料 博客日记

feign.codec.DecodeException: Could not extract response: no suitable HttpMessageConverter found for

2024-09-07 01:00:07基础资料围观184

本篇文章分享feign.codec.DecodeException: Could not extract response: no suitable HttpMessageConverter found for,对你有帮助的话记得收藏一下,看Java资料网收获更多编程知识

一、报错

Could not extract response: no suitable HttpMessageConverter found for response type [xxx] and content type [application/octet-stream] 

feign.codec.DecodeException: Could not extract response: no suitable HttpMessageConverter found for response type [xxx] and content type [application/octet-stream]

解释一下:就是Feign自带的转换器中,无法把[class XXX]转换成content type [XXX;XXX]

  • 在使用SpringCloud FeignClient的时候,经常的情况是我们希望返回的是一个application/json类型的返回,
  • 当返回是[application/octet-stream]类型或者其他自带转换器中没有的类型时,feign调用就会解析错误。

二、具体源码分析

(1)在 Springboot 默认处理器为 MappingJackson2HttpMessageConverter

用于将 Java 对象转换为 JSON 格式。

但是MappingJackson2HttpMessageConverter,只支持"application/json"类型;因此springboot没有找到合适的HttpMessageConverter,于是报出了上面的异常。

 (2)feign默认的Decoder为SpringDecoder

SpringDecoder的decode的过程:

  1. 判断目标类型合法的
  2. 利用Spring框架的消息转换器messageConverters来执行这个任务,并可以通过自定义器来customizers自定义转换器的行为
  3. 创建一个HttpMessageConverterExtractor对象,最终通过调用该对象的extractData方法将Feign的响应Response对象转化为Java对象

二、解决措施

解决该问题,可以自定义一个Feign的Decoder,只要添加MediaType.APPLICATION_OCTET_STREAM_VALUE类型的支持即可。

第一步:自定义一个Decoder:

import com.fasterxml.jackson.databind.ObjectMapper;
import feign.Response;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.StreamUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;


@Configuration
@Slf4j
public class FeignConfiguration {
    @Bean
    public Decoder feignDecoder() {
        return new CustomFeignDecoder();
    }

    public class CustomFeignDecoder implements Decoder {

        private final ObjectMapper objectMapper = new ObjectMapper();
        private final HttpMessageConverter<Object> messageConverter = new MappingJackson2HttpMessageConverter(objectMapper);

        @Override
        public Object decode(Response response, Type type) throws IOException {
            if (response.status() == HttpStatus.NO_CONTENT.value() || response.body() == null) {
                return null;
            }
            Collection<String> contentTypeHeader = response.headers().getOrDefault("Content-Type", Collections.singletonList(MediaType.APPLICATION_OCTET_STREAM_VALUE));
            log.info("Response headers:{}", response.headers());
            String contentType;
            if (contentTypeHeader != null && !contentTypeHeader.isEmpty()) {
                contentType = contentTypeHeader.iterator().next();
            } else {
                contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
            }
            MediaType mediaType = MediaType.parseMediaType(contentType);
            String body = StreamUtils.copyToString(response.body().asInputStream(), StandardCharsets.UTF_8);
            return messageConverter.read((Class<?>) type, new FakeHttpInputMessage(body, mediaType));
        }
    }

    public static class FakeHttpInputMessage implements org.springframework.http.HttpInputMessage {
        private final String body;
        private final MediaType mediaType;

        public FakeHttpInputMessage(String body, MediaType mediaType) {
            this.body = body;
            this.mediaType = mediaType;
        }

        @Override
        public InputStream getBody() throws IOException {
            return new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
        }

        @Override
        public org.springframework.http.HttpHeaders getHeaders() {
            org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders();
            headers.setContentType(mediaType);
            return headers;
        }
    }
}

首先获取默认的Content-Type值,如果没有,就返回一个MediaType.APPLICATION_OCTET_STREAM_VALUE类型的。

第二步:在Feign接口上加上:

configuration = FeignConfiguration.class

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;

@FeignClient(url = "${xxx.url:}", name = "TestFeignApi", configuration = FeignConfiguration.class)
public interface TestFeignApi {

    @PostMapping(path = "/aaa/bbb/checkUserTicket")
    UserResponse checkUserTicket(@RequestBody UserReq req,
                                 @RequestHeader("x-token") String token,
                                 @RequestHeader("x-id") String id);

}

这样问题就解决了~

========================================================================


文章来源:https://blog.csdn.net/m0_52767002/article/details/140603669
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云