美文网首页
FeignClient: no suitable HttpMes

FeignClient: no suitable HttpMes

作者: 千里行者 | 来源:发表于2019-12-02 18:38 被阅读0次

在使用SpringCloud FeignClient的时候,经常的情况是我们希望返回的是一个application/json类型的返回,但是有时候我们会碰到如下的错误

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

开启调试,跟踪代码到HttpMessageConverterExtractor类,关键方法如下

    public T extractData(ClientHttpResponse response) throws IOException {
        MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);
        if (!responseWrapper.hasMessageBody() || responseWrapper.hasEmptyMessageBody()) {
            return null;
        }
        MediaType contentType = getContentType(responseWrapper);

        for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
            if (messageConverter instanceof GenericHttpMessageConverter) {
                GenericHttpMessageConverter<?> genericMessageConverter =
                        (GenericHttpMessageConverter<?>) messageConverter;
                if (genericMessageConverter.canRead(this.responseType, null, contentType)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Reading [" + this.responseType + "] as \"" +
                                contentType + "\" using [" + messageConverter + "]");
                    }
                    return (T) genericMessageConverter.read(this.responseType, null, responseWrapper);
                }
            }
            if (this.responseClass != null) {
                if (messageConverter.canRead(this.responseClass, contentType)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Reading [" + this.responseClass.getName() + "] as \"" +
                                contentType + "\" using [" + messageConverter + "]");
                    }
                    return (T) messageConverter.read((Class) this.responseClass, responseWrapper);
                }
            }
        }

        throw new RestClientException("Could not extract response: no suitable HttpMessageConverter found " +
                "for response type [" + this.responseType + "] and content type [" + contentType + "]");
    }

远程接口由于各种问题没有在响应中设置content-type Header,导致FeignClient接收的时候contentType为null,HttpMessageConverterExtractor将其设置为MediaType.APPLICATION_OCTET_STREAM

    private MediaType getContentType(ClientHttpResponse response) {
        MediaType contentType = response.getHeaders().getContentType();
        if (contentType == null) {
            if (logger.isTraceEnabled()) {
                logger.trace("No Content-Type header found, defaulting to application/octet-stream");
            }
            contentType = MediaType.APPLICATION_OCTET_STREAM;
        }
        return contentType;
    }

但是this.messageConverters中的messageConverter中可以处理json类型响应的

解决方案就是配置Decoder,增加一个HttpMessageConverter,让其支持MediaType.APPLICATION_OCTET_STREAM

@Component
@FeignClient(url = "${host}", configuration = {MyFeignClient.Config.class})
interface MyFeignClient {
    @PostMapping("/call")
    ResponseEntity<Map<String, Object>> doCall(@RequestBody Map<String, String> param)

    @Slf4j
    static class Config{
        @Bean
        Decoder feignDecoder() {
            HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(customObjectMapper())
            List<MediaType> unmodifiedMediaTypeList = jacksonConverter.getSupportedMediaTypes()
            // 因为上条语句得到的是unmodified List类型,所以需要用另一个List进行操作
            List<MediaType> mediaTypeList = new ArrayList<>(unmodifiedMediaTypeList.size() + 1)
            mediaTypeList.addAll(unmodifiedMediaTypeList)
            mediaTypeList.add(MediaType.APPLICATION_OCTET_STREAM)
            jacksonConverter.setSupportedMediaTypes(mediaTypeList)
            ObjectFactory<HttpMessageConverters> objectFactory = new ObjectFactory<HttpMessageConverters>() {
                @Override
                HttpMessageConverters getObject() throws BeansException {
                    return new HttpMessageConverters(jacksonConverter)
                }
            }
            return new ResponseEntityDecoder(new SpringDecoder(objectFactory))
        }

        private static ObjectMapper customObjectMapper(){
            ObjectMapper objectMapper = new ObjectMapper()
            return objectMapper
        }
    }
}

相关文章

网友评论

      本文标题:FeignClient: no suitable HttpMes

      本文链接:https://www.haomeiwen.com/subject/wwvfgctx.html