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

相关推荐
Demon1_Coder20 小时前
跨域问题CORS
spring cloud
worilb21 小时前
Spring Cloud 学习与实践(6):Nacos 配置中心
数据库·学习·spring cloud
v***598321 小时前
SpringCloud实战十三:Gateway之 Spring Cloud Gateway 动态路由
java·spring cloud·gateway
JAVA社区2 天前
Java高级全套教程(十四)—— SpringData超详细实战详解
java·开发语言·spring cloud·面试·职场和发展
javahongxi2 天前
Spring Cloud Trace 链路实现
java·spring boot·spring cloud
小旭95272 天前
Spring Cloud 集成分布式日志 ELK+Swagger 接口文档实战
java·分布式·后端·elk·spring cloud
霸道流氓气质2 天前
Spring Cloud Nacos 服务注册 IP 选择机制与配置详解
tcp/ip·spring cloud·php
接着奏乐接着舞2 天前
springcloud xxl-job
后端·spring·spring cloud
jasnet_u2 天前
SpringCloud中Feign透传traceId及日志切面配置
java·spring cloud·feign·日志系统
JAVA面经实录9172 天前
SpringCloud 完整体系学习文档
java·spring cloud