一、问题重现


楼主在使用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. 关于java中生产者消费者模式的理解

    在说生产者消费者模式之前,我觉得有必要理解一下 Obj.wait(),与Obj.notify()方法.wait()方法是指在持有对象锁的线程调用此方法时,会释放对象锁,同时休眠本线程.notify() ...

  2. 石头剪刀布三局两胜(平局重来break用法)

  3. 大型NodeJS项目架构与优化

    使用场景: proxy(API冗余,跨域) vue ssr(服务端渲染) socket(大并发,通讯) 区块链(创业公司,新兴行业) 讨论什么? NodeJS异步IO原理及优化方案 NodeJS内存管 ...

  4. springMVC源码分析--FlashMap和FlashMapManager重定向数据保存

    在上一篇博客springMVC源码分析--页面跳转RedirectView(三)中我们看到了在RedirectView跳转时会将跳转之前的请求中的参数保存到fFlashMap中,然后通过FlashMa ...

  5. MyEclipse中把JSP默认编码改为UTF-8

    在MyEclispe中创建Jsp页面,Jsp页面的默认编码是“ISO-8859-1”,如下图所示: 在这种编码下编写中文是没有办法保存Jsp页面的,会出现如下的错误提示: 因此可以设置Jsp默认的编码 ...

  6. javafx实现模态/模式窗口

    import javafx.stage.*; import javafx.scene.*; import javafx.scene.paint.Color; import javafx.scene.c ...

  7. ERP商品类型管理相关业务处理(三十五)

    根据类型编号获取父类名称 -- ============================================= CREATE FUNCTION [dbo].[FN_getParentTyp ...

  8. Spring之hello world(Spring入门)

    spring各个版本中: 在3.0以下的版本,源码有spring中相关的所有包[spring功能 + 依赖包] 如2.5版本: 在3.0以上的版本,源码中只有spring的核心功能包[没有依赖包] ( ...

  9. sed & awk之sed

    sed处理文本的方法 sed在处理文本时,会先读取第一个输入行,将编辑命令应用于输入行,然后读取下一个输入行,并应用编辑命令.sed总是处理最新版本的行,因此sed中有多个编辑命令时,编辑命令的顺序对 ...

  10. 011 处理模型数据时@ModelAttribute的使用

    一:说明 1.使用场景 在下面的场景中: 使用new对象时,最后的效果是两个被赋值了,但是还有一个值是空值的,这个不符合只更新两个值,另一个值不变的情况. 正确的做法: 三个值得数据不是new出来的, ...