Springboot基于Redisson实现Redis分布式可重入锁源码解析
873
2022-08-20
使用feign发送http请求解析报错的问题
目录错误如下错误原因解决方案一解决方案二错误2
错误如下
发送请求开始
-----
[ChannelFeign#formRecog] ---> END HTTP (304117-byte body)
发送请求结束
返回开始
[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
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [channel.domain.ChannelResponse
可以看到返回的类型为[ChannelFeign#formRecog] content-type: text/json;charset=UTF-8
错误原因
接口返回为JSON格式数据但却将数据表示为了[text/json]导致Feign没有采用JSON解析器来解析,从而无法将响应数据转化为对应的POJO对象;
源码分析
feign客户端发送请求入口函数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();
}
// 分发请求
return dispatch.get(method).invoke(args);
}
decode()返回请求的解码函数
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(),提取数据
@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;
}
通过断点发现mediaType为接口返回的content-type:text/json类型。而supportedMediaType为application/json,所以返回false,找不到合适的转换器。
解决方案一
替代Feign的解码器,使json解析器同时解析[text/plain]的数据
// 创建一个新的转换器 解析微信的 [text/plain]
public class WxMessageConverter extends MappingJackson2HttpMessageConverter {
public WxMessageConverter(){
List
mediaTypes.add(MediaType.TEXT_PLAIN);
setSupportedMediaTypes(mediaTypes);
}
}
注入新的Decoder Feign将自动 替换
// 解决微信返回参数为[text/plain] 无法转化为json
@Bean
public Decoder feignDecoder(){
WxMessageConverter wxConverter = new WxMessageConverter();
ObjectFactory
return new SpringDecoder(objectFactory);
}
解决方案二
对返回的json字符串使用fastjosn转换
String result = channelFeign.formRecogTest(channelRequest);
ChannelResponse
new TypeReference
});
错误2
发送请求时对象转换json会自动将属性的首字母小写
解决方法:
//@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}
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~