FeignClient调用报错405请求方法错误

背景

  • FeignClient和GetMapping组合报错405请求方法错误
    在编写代码的时候,遇到一个情况,在使用FeignClient调用服务,因为是获得数据的接口,并且参数有很多,所以封装成一个DTO,但是却总是报错,报的还是很奇怪的405,请求方法错误,通过全局异常捕捉时,发现在服务端显示的是调用源POST调用,可是我明明使用FeignClient的GetMapping发起的。
    (因为想着在SpringMVC可以直接接收实体对象,并且@RequestParam并不能直接作用于一个实体对象上,所以就直接如下写了FeignClient)
@FeignClient("xdz-account-service")
public interface XdzAccountClient{
    @GetMapping("/xxx/xxx/xxx")
    Result getCmsMerchant(CmsMerchantDTO dto);
}

原因

事实上,通过分析造成如此的原因,我也整理了一下FeignClient的调用流程。这里先给出结论,为什么FeignClient发起的GetMapping会报405,是因为FeignClient最后是用HttpURLConnectiion发起的网络连接,在发起的过程中,Connection会判断其自身的body是否为空,如果不为空,则将 GET Method 转换为 POST Method。

这也容易理解,因为body数据只能放在RquestBody内以流的形式传输,而param数据则在Http协议中直接放在URL上进行传输和获取,所以如果有body数据,理应转为POST请求,这也每种数据都能正确的传输到网络接口。
在这里插入图片描述
但是,我们的服务端生产者是Get请求的接口,这样直接就会导致请求类型不一致报405,而为什么会造成转换,是因为body数据不为空,但是为什么body会有值,这要从初始化FeignClient和FeignClient的规则说起。
在启动过程中,就将FeignClient注解的类进行动态代理,且初始化了代理类。

  1. 如果有@RequestParam(“xx”)注解,则会将参数作为key,放入RequestTemplate.Factory中,由urlIndex来指明数组索引,并且在解析的时候,根据每个key从arg数组获取到具体值,拼接在url后面;
  2. 如果没有任何注解,或者用@RequestBody贴在参数前面,则初始化RequestTemplate.Factory的时候,bodyIndex会维护参数索引,并且bodyType这个参数会携带参数类型

所以我们现在的场景是没有加任何注解,FeignClient会把数据放入body中,那么怎么解决呢,可以直接加@RequestParam注解吗,如改写成下面这样?

@FeignClient("xdz-account-service")
public interface XdzAccountClient{
    @GetMapping("/xxx/xxx/xxx")
    Result getCmsMerchant(@RequestParam("dto") CmsMerchantDTO dto);
}

答案是否定的,因为@RequestParam只能注解单个基本数据类型,上面的写法将会让url的dto的值是dto.toString()。
我们可以将dto的数据全部拿出来,一个一个写在参数列表上,并都贴上@RequestParam注解,但是这样写法无异于让参数列表变的很长。

为此,如果我们要传递这种封装了多个数据的实体数据,又不想一个一个拿出来写在参数列表,我们在FeignClient中就要打破RESTful规范,使用POST来发起请求调用,同时服务端也使用POST来接收。
(按照上面的GET会转POST的理论,如果我们FeignClient调用端写的是GetMapping,参数不贴注解,只要服务端的生产者是PSOT请求加@RequestBody接收,那么也能正确接收并响应数据,经过实验发现确实如此)

下面是笔者在追踪源码的过程中整理的FeignClient调用流程

FeignClient调用流程

FeignClient调用流程

简化后主要流程

在这里插入图片描述

  • 23
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值