OpenFein的get请求无参数变post详解

今天向外域提供fein接口,get请求忘记写入@requesParam注解导致,fein直接变成了post请求,引发了我的好奇,为什么Spring mvc可以,他不可以昵,让我们从源码开始吧,顺便解析完整的fein请求链路:

先给完整链路

复制代码
Feign 请求完整链路:

1. ReflectiveFeign.FeignInvocationHandler.invoke()
   → 代理方法入口,确定请求的类及参数

2. SynchronousMethodHandler.invoke()
   → 通过 buildTemplateFromArgs.create(argv) 组装 RequestTemplate

3. feign.Contract.BaseContract.parseAndValidateMetadata()
   → 🔑 关键分叉点:判断参数是 param 还是 body
   → 未加 @RequestParam 的参数被识别为 body 参数

4. ReflectiveFeign.BuildFormEncodedTemplateFromArgs.resolve()
   → 未加注解走此路径 → encoder.encode() 将参数写入 body
   → 加了注解走 RequestTemplate.resolve() → 参数拼入 URL query

5. FeignBlockingLoadBalancerClient.execute()
   → 组装最终 URL,选择负载均衡客户端

6. JDK HttpURLConnection
   → 执行 connection.getOutputStream() 时
   → 🐛 JDK 内部惰性初始化机制强制将 Method 改写为 POST

1、走入fein-core的

复制代码
1)ReflectiveFeign.FeignInvocationHandler.invoke的代理方法,确定请求的类及参数等,

直到进入选择对应的负载均衡客户端,我这边的默认是第二个

复制代码
org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient类有buildRequest组装url,然后通过executeWithLoadBalancerLifecycleProcessing进入到
复制代码
org.springframework.cloud.openfeign.loadbalancer.LoadBalancerUtils的
复制代码
executeWithLoadBalancerLifecycleProcessing方法中feignClient.execute(feignRequest, options); 重新选择客户端调用,就进入到下面这张图了

是不是发现不对了,哈哈哈哈,回过头,发现是执行了

复制代码
OutputStream out = connection.getOutputStream();

就会变,刚开始我也没有搞明白,查阅资料说是JDK HttpURLConnection 的内部惰性初始化 + 强制改写 Method 导致的,好了找到问题,然后又有疑惑,怎么办尼,那就试试正确的方法,看看是怎么解析的。你会发现他不会走到这里,so,说明了,还有一个地方,在确认request.body()是不是为null的地方,这里也是一个因素

好了正确的,我们又要回到

fein-core的SynchronousMethodHandler组装请求的方法

复制代码
RequestTemplate template = buildTemplateFromArgs.create(argv);
复制代码
RequestTemplate template = resolve(argv, mutable, varBuilder);

然后一直走encode方法,就会发现有一个写入body的,但是他需要判断outputMessage!=null,

复制代码
不为 messageConverter instanceof GenericHttpMessageConverter

会把我们的值,自动判断为body

到这其实差不多就结束了,但是还会有个疑问

对的请求是怎样走的昵,我重新模拟了一下,只有没加注解的会走这个

复制代码
feign.ReflectiveFeign.BuildFormEncodedTemplateFromArgs.resolve

然后走encoder.encode方法,没加的是不会,所以还能继续往上推,RequestTemplate mutable的resolve如何定义的,

复制代码
feign.ReflectiveFeign.BuildTemplateByResolvingArgs.resolve

加上了注解就会走

复制代码
feign.RequestTemplate.resolve

所以现在问题原因已经定位到了,获取这个配置,导致resolve方法不一样

复制代码
RequestTemplate mutable = RequestTemplate.from(metadata.template());

那RequestTemplate是什么时候生成的昵,上代码

复制代码
feign.Contract.BaseContract.parseAndValidateMetadata方法

判断是什么参数的地方,param还是body,前面遗留的为什么不加requestParam会走body参数,是不是真相大白了

相关推荐
凤山老林21 小时前
微服务契约测试体系:Spring Cloud Contract/Pact 实战与 CI/CD 自动化 Mock 搭建
spring cloud·ci/cd·微服务
choumou_M1 天前
MySQL_1:数据库悲观锁
后端·spring·spring cloud
吴声子夜歌1 天前
Java面试——Spring Cloud原理及应用(二)
java·spring cloud·面试
夏天拐跑了西瓜2 天前
Eureka注册中心——单机与高可用集群搭建
java·spring cloud·微服务·eureka
就叫_这个吧2 天前
java springcloud熔断降级组件sentinel基础应用及nacos持久化处理
java·spring cloud·nacos·sentinel
仍然.3 天前
SpringCloud---Gateway
spring·spring cloud·gateway
手握风云-4 天前
Spring Cloud:分布式系统的“粘合剂”(六)
后端·spring·spring cloud
仍然.5 天前
SpringCloud---OpenFeign
spring boot·spring·spring cloud
手握风云-5 天前
Spring Cloud:分布式系统的“粘合剂”(五)
后端·spring·spring cloud
夏天拐跑了西瓜6 天前
Spring Cloud 微服务实战(三):一个服务挂了,凭什么拖垮整个系统?Sentinel 限流熔断实战
java·spring cloud·微服务