一、问题重现


楼主在使用feign进行声明式服务调用的时候发现,当GET请求为多参数时,为方便改用DTO对象进行参数传递。但是,在接口调用时feign会抛出一个405的请求方式错误:

{"timestamp":1540713334390,"status":405,"error":"Method Not Allowed", "exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/role/get"}

API接口层代码如下:

@RequestMapping(value = "/role")
public interface RoleService {
@GetMapping(value = "/get")
Result<RuleInfoVO> getRoleInfo(RoleInfoRequest request); }

服务端实现:

@Slf4j
@RestController
public class RoleInfoResource implements RoleService { @Override
public Result<RuleInfoVO> getRoleInfo(RoleInfoRequest request) {
log.info("params of getRoleInfo:{}",request);
return new Result<>();
}
}

feign客户端调用:

@Slf4j
@RestController
@RequestMapping(value = "/role")
public class RoleController { @Autowired
private RoleInfoApi roleInfoApi; @GetMapping(value = "/get")
public Result<RuleInfoVO> getRuleInfo(RoleInfoRequest request){
log.info("params of getRuleInfo:{}",request);
Result<RuleInfoVO> result = this.roleInfoApi.getRoleInfo(request);
log.info("result of getRuleInfo:{}",result);
return result;
}
}

检查feign调用方式与服务端所声明的方式一致,但是为什么为抛出405异常?带着该疑问稍微跟了一下源码,发现feign默认的远程调用使用的是jdk底层的HttpURLConnection,这在feign-core包下的Client接口中的convertAndSend方法可看到:

if (request.body() != null) {
if (contentLength != null) {
connection.setFixedLengthStreamingMode(contentLength);
} else {
connection.setChunkedStreamingMode(8196);
}
connection.setDoOutput(true);
OutputStream out = connection.getOutputStream();
if (gzipEncodedRequest) {
out = new GZIPOutputStream(out);
} else if (deflateEncodedRequest) {
out = new DeflaterOutputStream(out);
}
try {
out.write(request.body());
} finally {
try {
out.close();
} catch (IOException suppressed) { // NOPMD
}
}
}

该段代码片段会判断requestBody是否为空,我们知道GET请求默认是不会有requestBody的,因此该段代码会执行到HttpURLConnection中的 private synchronized OutputStream getOutputStream0() throws IOException; 方法:

 if (this.method.equals("GET")) {
this.method = "POST";
}

最关键的代码片段已显示当请求方式为GET请求,会将该GET请求修改为POST请求,这也就是4返回05状态的根本原因。

二、解决方案


幸运的是,feign为我们提供了相应的配置解决方案。我们只需将feign底层的远程调用由HttpURLConnection修改为其他远程调用方式即可。而且基本不需要修改太多的代码,只需再依赖中加入feign-httpclient包的依赖,并在@RequestMapping注解中加入consumes的属性即可:

 compile 'io.github.openfeign:feign-httpclient:9.5.1'

楼主用的gradle,使用maven的大佬请自行更改为maven的配置方式。

增加@GetMapping注解的consumes属性,使用@RequestMapping的大佬也一样:

 @RequestMapping(value = "/role")
public interface RoleService { @GetMapping(value = "/get",consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
Result<RuleInfoVO> getRoleInfo(@RequestBody RoleInfoRequest request); }

大功告成:

源代码请各位大佬移步:https://github.com/LJunChina/cloud-solution-staging

spring cloud——feign为GET请求时的对象参数传递的更多相关文章

  1. 使用Spring Cloud Feign 日志查看请求响应

    在使用微服务时,常常会用feign做客户端去调用别的微服务,但是在日志中很难查看到具体的请求和响应.因此,需要把feign默认的日志打开. 日志设置 创建feign配置类 @Configuration ...

  2. 笔记:Spring Cloud Feign 其他配置

    请求压缩 Spring Cloud Feign 支持对请求与响应进行GZIP压缩,以减少通信过程中的性能损耗,我们只需要通过下面二个参数设置,就能开启请求与响应的压缩功能,yml配置格式如下: fei ...

  3. 第六章:声明式服务调用:Spring Cloud Feign

    Spring Cloud Feign 是基于 Netflix Feign 实现的,整合了 Spring Cloud Ribbon 和 Spring Cloud Hystrix,除了提供这两者的强大功能 ...

  4. spring cloud feign不支持@RequestBody+ RequestMethod.GET,报错

    1.问题梳理: 异常:org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not ...

  5. 笔记:Spring Cloud Feign Ribbon 配置

    由于 Spring Cloud Feign 的客户端负载均衡是通过 Spring Cloud Ribbon 实现的,所以我们可以直接通过配置 Ribbon 的客户端的方式来自定义各个服务客户端调用的参 ...

  6. 笔记:Spring Cloud Feign 声明式服务调用

    在实际开发中,对于服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以我们通常会针对各个微服务自行封装一些客户端类来包装这些依赖服务的调用,Spring Cloud Feign 在此基础上做了进 ...

  7. Spring Cloud Feign Ribbon 配置

    由于 Spring Cloud Feign 的客户端负载均衡是通过 Spring Cloud Ribbon 实现的,所以我们可以直接通过配置 Ribbon 的客户端的方式来自定义各个服务客户端调用的参 ...

  8. RestTemplate OR Spring Cloud Feign 上传文件

    SpringBoot,通过RestTemplate 或者 Spring Cloud Feign,上传文件(支持多文件上传),服务端接口是MultipartFile接收. 将文件的字节流,放入ByteA ...

  9. 第六章 声明式服务调用: Spring Cloud Feign

    我们在使用 Spring Cloud Ribbon 时, 通常都会利用它对 RestTemplate 的请求拦截来实现对依赖服务的接口调用, 而 RestTemplate 已经实现了对 HTTP 请求 ...

随机推荐

  1. tomcat8配置SSL

    参考网址:http://www.micmiu.com/enterprise-app/sso/sso-cas-sample/#viewSource 1.生成证书 keytool -genkey -ali ...

  2. centos7 部署 open-falcon 0.2.1

    =============================================== 2019/4/28_第1次修改                       ccb_warlock 更新 ...

  3. 在Linux上安装go-gtk

    由于Linux的Gnome桌面就是用GTK编写的,所以,Linux本身就包含GTK工具库,安装GTK工具库在线安装即可. 第一步:在终端输入: sudo apt-get install libgtk3 ...

  4. MySQL双版本共存解决方案

    案例是MySQL5.5(3306端口)和MySQL5.6(3307端口). 1. 修改C:\Program Files (x86)\MySQL\MySQL Server 5.6\下的my-xxx.in ...

  5. linux 下 eclipse 安装

    下载: 官网选择相应安装包下载,我这里下了tar.gz包 安装: tar xzvf eclipse-inst-linux64.tar.gz 设置环境变量 export JAVA_HOME=/usr/l ...

  6. Codeforces 999F Cards and Joy(二维DP)

    题目链接:http://codeforces.com/problemset/problem/999/F 题目大意:有n个人,n*k张卡牌,每个人会发到k张卡牌,每个人都有一种喜欢的卡牌f[i],当一个 ...

  7. poj3481 splaytree模板题

    找不到错在哪里,先留着吧 /* splay是以键值排序的! 三个操作:1 a b,z增加键值为b的点,值为a 2,查询最大值 3,查询最小值 需要的操作:rotate,splay,insert,fin ...

  8. python接口自动化测试十四: 用正则表达式提取数据

    import requests import re url = 'xxxx' r = requests.post(url) # 正则公式: postid = re.findall(r"(.+ ...

  9. python接口自动化测试四:代码发送HTTPS请求

    HTTPS: get: url = 'https://www.juhe.cn/docs/api/id/39' r = requests.get(url)                       # ...

  10. python 全栈开发,Day19(组合,组合实例,初识面向对象小结,初识继承)

    一.组合 表示的一种什么有什么的关系 先来说一下,__init__的作用 class Dog: def __init__(self, name, kind, hp, ad): self.name = ...