美文网首页
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