错误如下
发送请求开始
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