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参数,是不是真相大白了

相关推荐
rebibabo5 小时前
Java进阶(1) | 微服务入门:从单体到 Spring Cloud 全家桶
spring cloud·微服务·nacos·openfeign·服务注册与发现·java进阶·单体架构
乐观的Terry1 天前
3、数据库设计与领域实体
java·数据库·spring boot·spring cloud·ai编程
吃饱了得干活1 天前
Spring Cloud Gateway限流:从Redis到Sentinel的三种方案
后端·spring cloud
Java小白笔记3 天前
Docker 命令大全:从入门到精通的完整指令集
spring cloud·docker
光学补偿3 天前
微服务学习 --- Spring Cloud概述
学习·spring cloud·微服务
不能只会打代码3 天前
校享云 — 高校智慧后勤平台微服务架构设计与实践
spring cloud·docker·微服务·nacos·vue·校享云
LiaoWL1233 天前
【SpringCloud合集-06】Spring Cloud Gateway网关学习笔记
笔记·学习·spring cloud
乐观的Terry4 天前
1、为什么要自己造发布系统
java·spring boot·后端·spring cloud·架构
HZZD_HZZD4 天前
从单体到微服务:能源计费系统的领域拆分、数据一致性与Spring Cloud实战落地
spring cloud·微服务·能源
LiaoWL1235 天前
【SpringCloud合集-04】Sentinel 流量控制与熔断降级 学习笔记
学习·spring cloud·sentinel