好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

使用feign发送http请求解析报错的问题

错误如下

发送请求开始

?

1

2

-----

[ChannelFeign#formRecog] ---> END HTTP (304117-byte body)

发送请求结束

返回开始

?

1

2

3

4

5

6

7

8

[ChannelFeign#formRecog] <--- HTTP/1.1 200 OK (4948ms)

[ChannelFeign#formRecog] content-length: 5207

[ChannelFeign#formRecog] content-type: text/json;charset=UTF-8

[ChannelFeign#formRecog] date: Mon, 08 Oct 2018 10:47:03 GMT

[ChannelFeign#formRecog] x-vcap-request-id: c323f65a-12e6-4604-7393-a4bf0ca403d5

[ChannelFeign#formRecog] 

[ChannelFeign#formRecog] {json格式的数据}

[ChannelFeign#formRecog] <--- END HTTP (5207-byte body)

返回结束

ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.codec.DecodeException: Could not extract response: no suitable HttpMessageConverter found for response type [channel.domain.ChannelResponse<TableData>] and content type [text/json;charset=UTF-8]] with root cause
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [channel.domain.ChannelResponse<TableData>] and content type [text/json;charset=UTF-8]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:110) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.cloud.netflix.feign.support.SpringDecoder.decode(SpringDecoder.java:59) ~[spring-cloud-netflix-core-1.3.6.RELEASE.jar:1.3.6.RELEASE]
    at org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder.decode(ResponseEntityDecoder.java:47) ~[spring-cloud-netflix-core-1.3.6.RELEASE.jar:1.3.6.RELEASE]
    at feign.SynchronousMethodHandler.decode(SynchronousMethodHandler.java:165) ~[feign-core-9.5.0.jar:?]
    at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:133) ~[feign-core-9.5.0.jar:?]
    at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76) ~[feign-core-9.5.0.jar:?]
    at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-9.5.0.jar:?]

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [channel.domain.ChannelResponse<TableData>] and content type [text/json;charset=UTF-8]

可以看到返回的类型为[ChannelFeign#formRecog] content-type: text/json;charset=UTF-8

错误原因

接口返回为JSON格式数据但却将数据表示为了[text/json]导致Feign没有采用JSON解析器来解析,从而无法将响应数据转化为对应的POJO对象;

源码分析

feign客户端发送请求入口函数invoke()

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

      if ( "equals" .equals(method.getName())) {

        try {

          Object

              otherHandler =

              args.length > 0 && args[ 0 ] != null ? Proxy.getInvocationHandler(args[ 0 ]) : null ;

          return equals(otherHandler);

        } catch (IllegalArgumentException e) {

          return false ;

        }

      } else if ( "hashCode" .equals(method.getName())) {

        return hashCode();

      } else if ( "toString" .equals(method.getName())) {

        return toString();

      }

      // 分发请求

      return dispatch.get(method).invoke(args);

    }

decode()返回请求的解码函数

?

1

2

3

4

5

6

7

8

9

   Object decode(Response response) throws Throwable {

    try {

      return decoder.decode(response, metadata.returnType());

    } catch (FeignException e) {

      throw e;

    } catch (RuntimeException e) {

      throw new DecodeException(e.getMessage(), e);

    }

   }

进入decode.decode(),提取数据

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

@Override

     @SuppressWarnings ({ "unchecked" , "rawtypes" , "resource" })

     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 + "]" );

     }

进入genericMessageConverter.canRead(this.responseType, null, contentType) 

?

1

2

3

4

5

6

7

8

9

10

11

     protected boolean canRead(MediaType mediaType) {

         if (mediaType == null ) {

             return true ;

         }

         for (MediaType supportedMediaType : getSupportedMediaTypes()) {

             if (supportedMediaType.includes(mediaType)) {

                 return true ;

             }

         }

         return false ;

     }

通过断点发现mediaType为接口返回的content-type:text/json类型。而supportedMediaType为application/json,所以返回false,找不到合适的转换器。 

解决方案一

替代Feign的解码器,使json解析器同时解析[text/plain]的数据

?

1

2

3

4

5

6

7

8

// 创建一个新的转换器 解析微信的 [text/plain] 

public class WxMessageConverter extends MappingJackson2HttpMessageConverter {

    public WxMessageConverter(){

        List<MediaType> mediaTypes = new ArrayList<>();

        mediaTypes.add(MediaType.TEXT_PLAIN);

        setSupportedMediaTypes(mediaTypes);

    }

}

注入新的Decoder Feign将自动 替换

?

1

2

3

4

5

6

7

// 解决微信返回参数为[text/plain] 无法转化为json

@Bean

public Decoder feignDecoder(){

    WxMessageConverter wxConverter = new WxMessageConverter();

    ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(wxConverter);

    return new SpringDecoder(objectFactory);

}

解决方案二

对返回的json字符串使用fastjosn转换

?

1

2

3

4

        String result = channelFeign.formRecogTest(channelRequest);

        ChannelResponse<TableData> hello = JSONObject.parseObject(result,

                new TypeReference<ChannelResponse<TableData>>() {

                });

错误2

发送请求时对象转换json会自动将属性的首字母小写

解决方法:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

//@Data

public class ChannelRequest {

    //@JSONField(name="Header")

    @JsonProperty

    private ChannelReqHead Header;

    //@JSONField(name="Body")

    @JsonProperty

    private ChannelReqBody Body;

    

    // 如果get方法上不加JsonIgnore,jason化时小写header也会出现

    @JsonIgnore

    public ChannelReqHead getHeader() {

        return Header;

    }

    @JsonIgnore

    public void setHeader(ChannelReqHead header) {

        Header = header;

    }

    @JsonIgnore

    public ChannelReqBody getBody() {

        return Body;

    }

    @JsonIgnore

    public void setBody(ChannelReqBody body) {

        Body = body;

    }    

}

使用jsonField不起作用,不使用jsonIgnore会生成大写和小写

如:{[Header]:xxx,"header":xxx}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/yangchuanan/article/details/82976877

查看更多关于使用feign发送http请求解析报错的问题的详细内容...

  阅读:13次