使用feign發(fā)送http請求解析報錯的問題
錯誤如下
發(fā)送請求開始
----- [ChannelFeign#formRecog] ---> END HTTP (304117-byte body)
發(fā)送請求結(jié)束
返回開始
[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格式的數(shù)據(jù)} [ChannelFeign#formRecog] <--- END HTTP (5207-byte body)
返回結(jié)束
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格式數(shù)據(jù)但卻將數(shù)據(jù)表示為了[text/json]導(dǎo)致Feign沒有采用JSON解析器來解析,從而無法將響應(yīng)數(shù)據(jù)轉(zhuǎn)化為對應(yīng)的POJO對象;
源碼分析
feign客戶端發(fā)送請求入口函數(shù)invoke()
? ? @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(); ? ? ? } ? ? ? // 分發(fā)請求 ? ? ? return dispatch.get(method).invoke(args); ? ? }
decode()返回請求的解碼函數(shù)
? 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(),提取數(shù)據(jù)
@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)
?? ?protected boolean canRead(MediaType mediaType) { ?? ??? ?if (mediaType == null) { ?? ??? ??? ?return true; ?? ??? ?} ?? ??? ?for (MediaType supportedMediaType : getSupportedMediaTypes()) { ?? ??? ??? ?if (supportedMediaType.includes(mediaType)) { ?? ??? ??? ??? ?return true; ?? ??? ??? ?} ?? ??? ?} ?? ??? ?return false; ?? ?}
通過斷點發(fā)現(xiàn)mediaType為接口返回的content-type:text/json類型。而supportedMediaType為application/json,所以返回false,找不到合適的轉(zhuǎn)換器。
解決方案一
替代Feign的解碼器,使json解析器同時解析[text/plain]的數(shù)據(jù)
// 創(chuàng)建一個新的轉(zhuǎn)換器 解析微信的 [text/plain]? public class WxMessageConverter extends MappingJackson2HttpMessageConverter { ? ? public WxMessageConverter(){ ? ? ? ? List<MediaType> mediaTypes = new ArrayList<>(); ? ? ? ? mediaTypes.add(MediaType.TEXT_PLAIN); ? ? ? ? setSupportedMediaTypes(mediaTypes); ? ? } }
注入新的Decoder Feign將自動 替換
// 解決微信返回參數(shù)為[text/plain] 無法轉(zhuǎn)化為json @Bean public Decoder feignDecoder(){ ? ? WxMessageConverter wxConverter = new WxMessageConverter(); ? ? ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(wxConverter); ? ? return new SpringDecoder(objectFactory); }
解決方案二
對返回的json字符串使用fastjosn轉(zhuǎn)換
? ? ? ? String result = channelFeign.formRecogTest(channelRequest); ? ? ? ? ChannelResponse<TableData> hello = JSONObject.parseObject(result, ? ? ? ? ? ? ? ? new TypeReference<ChannelResponse<TableData>>() { ? ? ? ? ? ? ? ? });
錯誤2
發(fā)送請求時對象轉(zhuǎn)換json會自動將屬性的首字母小寫
解決方法:
//@Data public class ChannelRequest { ? ? //@JSONField(name="Header") ? ? @JsonProperty ? ? private ChannelReqHead Header; ? ? //@JSONField(name="Body") ? ? @JsonProperty ? ? private ChannelReqBody Body; ? ?? ? ? // 如果get方法上不加JsonIgnore,jason化時小寫header也會出現(xiàn) ? ? @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}
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- springcloud-feign調(diào)用報錯問題
- 如何解決使用restTemplate進行feign調(diào)用new HttpEntity<>報錯問題
- 解決Spring調(diào)用Feign報錯:java.io.IOException:Incomplete output stream問題
- @FeignClient?path屬性路徑前綴帶路徑變量時報錯的解決
- 通過FeignClient調(diào)用微服務(wù)提供的分頁對象IPage報錯的解決
- Springcloud?feign傳日期類型參數(shù)報錯的解決方案
- 解決配置Feign時報錯PathVariable annotation was empty on param 0.
相關(guān)文章
Spring Boot啟動過程(六)之內(nèi)嵌Tomcat中StandardHost、StandardContext和Sta
這篇文章主要介紹了Spring Boot啟動過程(六)之內(nèi)嵌Tomcat中StandardHost、StandardContext和StandardWrapper的啟動教程詳解,需要的朋友可以參考下2017-04-04java操作excel導(dǎo)入導(dǎo)出的3種方式
項目需要,要實現(xiàn)一個導(dǎo)入導(dǎo)出excel的功能,于是任務(wù)驅(qū)動著我學(xué)習(xí)到了POI、easypoi和easyexcel這3個java操作Excel的工具,下面這篇文章主要給大家介紹了關(guān)于java操作excel導(dǎo)入導(dǎo)出的3種方式,需要的朋友可以參考下2023-05-05Java+MySQL實現(xiàn)圖書管理系統(tǒng)(完整代碼)
這篇文章主要介紹了Java+MySQL實現(xiàn)圖書管理系統(tǒng)(完整代碼),本文給大家介紹的非常想詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01Java為何需要平衡方法調(diào)用與內(nèi)聯(lián)
這篇文章主要介紹了Java為何需要平衡方法調(diào)用與內(nèi)聯(lián),幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01