首页 > 基础资料 博客日记
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的过程:
- 判断目标类型合法的
- 利用Spring框架的消息转换器messageConverters来执行这个任务,并可以通过自定义器来customizers自定义转换器的行为
- 创建一个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进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签: