今天向外域提供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 改写为 POST1、走入fein-core的1ReflectiveFeign.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的但是他需要判断outputMessagenull不为 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参数是不是真相大白了