使用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<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()

    @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<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.TEXT_PLAIN);
        setSupportedMediaTypes(mediaTypes);
    }
}

注入新的Decoder Feign将自动 替换

// 解决微信返回参数为[text/plain] 无法转化为json
@Bean
public Decoder feignDecoder(){
    WxMessageConverter wxConverter = new WxMessageConverter();
    ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(wxConverter);
    return new SpringDecoder(objectFactory);
}

解决方案二

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

        String result = channelFeign.formRecogTest(channelRequest);
        ChannelResponse<TableData> hello = JSONObject.parseObject(result,
                new TypeReference<ChannelResponse<TableData>>() {
                });

错误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}

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

(0)

相关推荐

  • 使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务的方法(推荐)

    在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.我们可以使用JDK原生的URLConnection.Apache的Http Client.Netty的异步HTTP Client, Spring的RestTemplate.但是,用起来最方便.最优雅的还是要属Feign了. Feign简介 Feign是一种声明式.模板化的HTTP客户端.在Spring Cloud中使用Feign, 我们可以做到使用HTT

  • 解决FeignClient发送post请求异常的问题

    FeignClient发送post请求异常 这个问题其实很基础.但是却难倒了我.记录一下 在发送post请求的时候要指定消息格式 正确的写法是这样 @PostMapping(value = "/test/post", consumes = "application/json") String test(@RequestBody String name); 不生效的写法 @PostMapping(value = "/test/post", prod

  • @FeignClient 实现简便http请求封装方式

    目录 @FeignClient实现http请求封装 使用流程 将http请求封装为FeignClient 1.配置拦截器 2.注入feignClientbean 3.配置pom引用 4.写feignClient 5.写熔断器 @FeignClient实现http请求封装 我们一般在代码中调用http请求时,都是封装了http调用类,底层自己定义请求头,在写的时候,也是需要对返回的值进行json解析,很不方便. name:name属性会作为微服务的名称,用于服务发现 url:host的意思,不用加

  • Java 如何使用Feign发送HTTP请求

    在往常的 HTTP 调用中,一直都是使用的官方提供的 RestTemplate 来进行远程调用,该调用方式将组装代码冗余到正常业务代码中,不够优雅,因此在接触到 Feign 后,考虑使其作为一个 HTTP 发送基础,来进行远程调用. 下面就让我们来看一下,其是如何使用的. 引入依赖 首先,我们需要将 Feign 的基础依赖引入项目,因为我们只使用 Feign 的 remote 功能,因此,只引入基础依赖. 此外在项目中,我们还自定义了了 JSON 转换和 log 设置,因此还需要引入这些的第三方

  • 使用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] conten

  • node.js请求HTTPS报错:UNABLE_TO_VERIFY_LEAF_SIGNATURE\的解决方法

    发现错误 最近在用Nodejs发送https请求时候,出现\"Error: UNABLE_TO_VERIFY_LEAF_SIGNATURE\"的错误,错误如下: events.js:72 throw er; // Unhandled \'error\' event ^ Error: UNABLE_TO_VERIFY_LEAF_SIGNATURE at SecurePair. (tls.js:1381:32) at SecurePair.emit (events.js:92:17) at

  • Python发送http请求解析返回json的实例

    python发起http请求,并解析返回的json字符串的小demo,方便以后用到. #! /usr/bin/env python # -*- coding:gbk -*- import os import sys import json import urllib import urllib2 if __name__ == "__main__": query_file = sys.argv[1] query_index = 0 with open(query_file, 'r') a

  • 解决vue 使用axios.all()方法发起多个请求控制台报错的问题

    今天在项目中使用axios时发现axios.all() 方法可以执行但是控制台报错,后来在论坛中看到是由于axios.all() 方法并没有挂载到 axios对象上,需要我们手动去添加 == 只需要在你封装的axios文件里加入 == instance.all = axios.all 就完美解决了! 补充知识:vue项目中使用axios.all处理并发请求报_util2.default.axios.all is not a function异常 报错: _util2.default.axios.

  • Web安全解析报错注入攻击原理

    目录 1.报错注入攻击 2.报错注入代码分析 1.报错注入攻击 报错注入攻击的测试地址:http://127.0.0.1/sqli/error.php?username=1. 访问该网址时,页面返回ok,如图28所示. 图28 访问username=1时页面的的结果 访问http://127.0.0.1/sqli/error.php?username=1',因为参数username的值是1',在数据库中执行SQL时,会因为多了一个单引号而报错,输出到页面的结果如图29所示. 图29 访问user

  • Python2包含中文报错的解决方法

    发现问题 最近在工作中遇到一个问题,通过查找相关的解决方法终于解决,下面话不多说了,来一起看看详细的介绍吧 命令行会出现如下错误信息 SyntaxError: Non-ASCII character '\xe8' in file Python注释.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details 解决方法如下: 在代码的最顶部添加 #coding=utf-8 .

  • Vue3发送post请求出现400 Bad Request报错的解决办法

    查了一下网上资料,报400一般无非就是两种: 1. Bad Request:“错误的请求" 2. Invalid Hostname:"不存在的域名” 在这里我的报错是因为前端请求头的content-type和后端不一致. 一般后端默认的内容类型是 application/x-www-form-urlencoded,而axios默认的是 applecation/json. 但是也有例外,要根据后端的注解来区分我们要转换的类型. 根据上一篇笔记上说的: @RequestBody 用 con

  • Springcloud feign传日期类型参数报错的解决方案

    目录 feign传日期类型参数报错 Date类型参数报错 LocalDate类型报错 feign传参问题及传输Date类型参数时差的坑 下面说说两种解决方案 feign传参时候使用@DateTimeFormat注解的坑 feign传日期类型参数报错 Date类型参数报错 在Spring cloud feign接口中传递Date类型参数时报错,报错信息. 场景: 客户端传递一个new Date()的参数,服务端接受的参数和客户端有时间差. 客户端打印格式化的new Date(): 2018-05-

  • spring cloud feign不支持@RequestBody+ RequestMethod.GET报错的解决方法

    1.问题梳理: 异常:org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported 很明显是最终feign执行http请求时把这个方法认定为POST,但feign client中又定义了RequestMethod.GET 或 @GetMapping,冲突导致报错 那么为什么feign会认为这个方法是post呢? 源码追踪: 1.我们从feignClient注解

随机推荐