关于OpenFeign 接口参数定义的问题

文章目录

  • 前言
  • 一、声明GET请求实际用POST ?
    • 1.1 例子:
    • 1.2 原因:
  • 二、GET请求放入了参数值却找不到?
    • 2.1 例子:
    • 2.2 原因:
    • 2.3 spring-mvc http 请求中为什么可以:
  • 三、异步线程无法调用feign 接口 ?
    • 3.1 例子:
    • 3.2 原因:
  • 四、feign header 相同名字请求头合并 ?
  • 总结


前言

在使用feign 接口进行远程或者内部服务间的方法调用时,有时会遇到明明声明了GET请求,但是feign 依然使用POST进行发送,或者使用GET 请求是明明已经放入了参数,依然提示参数值是空的,使用了异步线程调用feign 接口总是失效。


提示:以下是本篇文章正文内容,下面案例可供参考

一、声明GET请求实际用POST ?

1.1 例子:

@GetMapping("/api/test1")
R<Boolean> test1(@RequestHeader("token') String token,String endTime);

报错:
在这里插入图片描述

1.2 原因:

  • Feign 在默认情况下会将所有的请求方法都认为是 GET 请求。但是,如果请求的方法参数没有被注解标注,或者只使用了 @RequestBody 注解,那么 Feign 会将请求方法自动处理为 POST 请求(因为它认为可能有参数需要在请求体中发送)。

  • 如果 Feign 的接口方法参数没有被 @RequestParam 或 @PathVariable 等注解标注,则 Feign 会将该请求当作是 POST 请求,并且尝试将参数放到 POST 请求的请求体中去,即使你的方法在定义时倾向于 GET 请求

  • 此规则源自于 Feign 的设计原则,它认为如果方法参数没有任何注解(或者只有 @RequestBody 注解),那么这些参数应该处于请求体中,而请求体一般的使用场景是在 POST 或者 PUT 请求中,所以 Feign 采用了 POST 请求作为默认值。

  • 如果你希望使用 GET 请求并且参数需要在 URL 中传递,那么你需要为方法参数添加 @RequestParam 或 @PathVariable 等注解,这样 Feign 就会将这些参数添加到 GET 请求的 URL 中,而不是采用 POST 的方式。

二、GET请求放入了参数值却找不到?

2.1 例子:

@GetMapping("/api/test2")
R<Boolean> test2(@RequestHeader("token') String token,@RequestParam String endTime);

报错:
在这里插入图片描述

2.2 原因:

  • Feign无法获取未标注@RequestParam的参数名称,这是因为Java编译器默认是不会把方法的参数名称编译进入class文件中的

  • Java编译器在编译程序源码的时候,只会保留方法的参数类型和参数的顺序,但不会保留参数名称。也就是说,在.class文件中,方法的参数名称被替换为了通用的名称,比如arg0, arg1, arg2等。原本的参数名称信息在编译后就丢失了。而因为 Feign 是在运行时通过反射解析方法签名来构造请求,所以它无法获取未标注@RequestParam的参数名称。

  • -在Spring Cloud中使用Feign时,@RequestParam注解用于将方法参数绑定到请求的query参数。在Feign中,如果你将一个方法参数标注为@RequestParam却没有为它指定具体的参数名,那么Feign在构建请求时就无法知道这个参数应该绑定到query参数的哪一个名称上。

  • 这种情况在所有使用了反射机制的 Java 程序中都会遇到,不仅仅是 Feign。为了解决这个问题,Java 提供了一种方式将参数名称保留在 .class 文件中,需要在编译时使用 -parameters 选项,或者在源码中用 @Param 这样的注解显式提供参数名。

  • 所以,在使用 Feign 的时候你必须为@RequestParam注解指定参数名称,这样Feign在运行时就能通过这个名称知道应该如何绑定参数到请求。例如:@RequestParam(“name”) String name,这样 Feign 就知道应该将这个参数值放到请求中名为"name"的参数内。

2.3 spring-mvc http 请求中为什么可以:

Spring MVC 可以通过其他方式获取到方法参数的名称。Spring 内部使用了一种叫做 LocalVariableTableParameterNameDiscoverer的技术,它使用了 Java 字节码操作库 ASM 来分析 .class 文件的局部变量表(Local Variable Table),以此来获取方法参数的名称。对于 Feign 而言,它并没有内置这样的机制来获取方法参数的名称,所以就需要显式指定 @RequestParam 的 name。

当你在Spring MVC中创建一个Controller方法来处理HTTP请求时,方法参数和请求参数之间的绑定可以通过多种方式实现。

比如,你可以在方法中直接使用与请求参数相同名字的参数,Spring MVC会自动匹配。这是因为Spring MVC在处理请求时,会利用Java反射机制获取方法参数的名称,然后根据名称去匹配请求中的参数。这得益于Spring框架的一部分叫做DataBinder,它负责将请求参数映射到控制器方法的参数。

假设你的HTTP请求是这样的:

GET /some-endpoint?name=John

你的controller方法可以是这样的:

@GetMapping("/some-endpoint")
public String sayHello(String name) {return "Hello, " + name;
}

你可以看到,并没有显式使用@RequestParam注解,Spring MVC在处理请求时已经自动将请求参数"name"绑定到了方法参数name上。

然而,这只在Spring MVC中有效。对于Feign来说,这种机制就不适用了,因此须显式指定@RequestParam的name。

三、异步线程无法调用feign 接口 ?

3.1 例子:

 private static ExecutorService executor = Executors.newFixedThreadPool(2);CompletableFuture<Void> bFuture = CompletableFuture.runAsync(() -> {/远程调用B服务,查某数据。}, executor);bFuture.get();

feing 接口没有调通,而且没有日志输出:

3.2 原因:

在使用Feign进行服务调用时,如果在新的线程内部进行Feign接口调用无效或失败,这个问题通常与Spring Cloud的上下文传递有关;Spring Cloud中的许多特性(例如Hystrix,Ribbon, Feign等)都依赖于ThreadLocal存储上下文或其它信息。如果在新的线程中启动了一个Feign调用,新线程通常不会继承主线程的ThreadLocal,所以这可能导致调用失败
所以这里需要线程主线程拿到上下文然后进行调用:

 private static ExecutorService executor = Executors.newFixedThreadPool(2);
//获取"主线程"的请求上下文RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();CompletableFuture<Void> bFuture = CompletableFuture.runAsync(() -> {//将"主线程"的请求上下文,设置在当前“异步线程上下文”中。RequestContextHolder.setRequestAttributes(requestAttributes);//2、远程调用B服务,查某数据。}, executor);// 本地单元测试打开下面一行,用于阻塞主线程//    CompletableFuture.allOf(bFuture).get();

如果在本地进行单元测试,因为主线程走完后,容器就被关闭了,所以需要阻塞主线程,这样子线程才能正常执行;

四、feign header 相同名字请求头合并 ?

Feign在处理请求头时,默认情况会合并具有相同名字的参数。合并后的值将作为单个请求头的值发送。例如,在Feign接口定义中有两个相同名字的请求头参数:


@FeignClient(name = "example", url = "http://example.com")
public interface ExampleClient {@RequestMapping(method = RequestMethod.GET, value = "/api/example")ResponseEntity<String> getData(@RequestHeader("header") String header1, @RequestHeader("header") String header2);
}

当调用该方法时,传入不同的值给这两个参数:

exampleClient.getData("value1", "value2");

Feign发送请求时,将会合并这两个参数的值,并作为单个请求头发送给服务端:

header: value1, value2
注意,这里的参数名是与请求头的键名相同的,导致它们会被自动合并为单个请求头的值。如果不希望请求参数被合并,需要设置参数的名称应该设置不相同。
在项目开发中通常会对feign 接口 实现 RequestInterceptor 对其传递 的参数统一作处理,此时就需要注意我们在调用feign 接口方法是否对请求头设置了相同的参数名,导致接口调用异常。

总结

本文对feign 接口在使用过程中遇到的常见问题,进行分析以及给出解决办法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/138695.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python经典练习题(一)

文章目录 &#x1f340;第一题&#x1f340;第二题&#x1f340;第三题&#x1f340;第四题&#x1f340;第五题 &#x1f340;第一题 有四个数字&#xff1a;1、2、3、4&#xff0c;能组成多少个互不相同且无重复数字的三位数&#xff1f;各是多少&#xff1f; 这里我们使用…

【开关稳压器】LMR16030SDDA、LMR38010FDDAR,汽车类LMR43610MSC5RPERQ1低 EMI 同步降压稳压器

一、LMR16030SDDA 开关稳压器 IC REG BUCK ADJ 3A 8SOPWR LMR16030 是一款带有集成型高侧 MOSFET 的 60V、3A SIMPLE SWITCHER 降压稳压器。该器件具有4.3V 至 60V 的宽输入范围&#xff0c;适用于从工业到汽车各类应用中非稳压电源的电源调节。该稳压器在睡眠模式下的静态电流…

leetcode:70. 爬楼梯

一、题目 函数原型&#xff1a;int climbStairs(int n) 二、思路 此题运用递归思想。当只有1个台阶&#xff0c;那么只有1种方法爬到楼顶——跨一个台阶&#xff1b;当有2个台阶时&#xff0c;有2种方法爬到楼顶——跨一个台阶跨两次或直接跨两个台阶。当有3个台阶或更多台阶时…

vue之 h() 函数

前言 Vue推荐在绝大数情况下使用模板来创建HTML&#xff0c;然后一些特殊的场景&#xff0c;你真的需要JavaScript的完全编程的能力&#xff0c;这个时候你可以使用渲染函数 &#xff0c;它比模板更接近编译器&#xff1b; h()函数是什么 Vue在生成真实的DOM之前&#xff0c…

Java LinkedList类详解

目录 什么是LinkedList LinkedList的使用 LinkedList的构造 LinkedList的其他常用方法的介绍 LinkedList的遍历 ArrayList和LinkedList的区别 什么是LinkedList LinkList的底层是双向链表结构&#xff0c;由于链表没有将元素存储在连续的空间中&#xff0c;元素存储在单独…

[C++随笔录] vector模拟实现

vector模拟实现 基本结构天选之子构造拷贝构造析构operator 空间reserveresizesize && capacity 增insertpush_back 删erasepop_back 查 && 改swapoperator[] 源码 基本结构 // 可以是不同类型, 用类模板 template <class T> class vector { public:// 源…

画一个时钟(html+css+js)

这是一个很简约的时钟。。。。。。。 效果&#xff1a; 代码&#xff1a; <template><div class"demo-box"><div class"clock"><ul class"mark"><liv-for"(rotate, index) in rotatedAngles":key"i…

VBA技术资料MF59:从二维变体数组中删除一行数据

【分享成果&#xff0c;随喜正能量】小小的善业&#xff0c;能赢来大的利益&#xff0c;小小的恶业&#xff0c;同样也能招致严重的后果。这正如古语所云&#xff1a;“莫以善小而不为&#xff0c;莫以恶小而为之。。 我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效…

想学嵌入式开发,薪资怎么样?

想学嵌入式开发&#xff0c;薪资怎么样&#xff1f; 对于嵌入式工程师来说呢&#xff0c;它重点学习内容就是首先一定要打好基础&#xff0c;如果从编程语言角度来讲&#xff0c;那么可以在语言上选C或者C&#xff0c;你可以选择其中任何一门语言作为你的入门。 最近很多小伙伴…

Unity之NetCode多人网络游戏联机对战教程(1)

文章目录 1.什么是NetCode2.安装NGO 1.什么是NetCode 官网链接&#xff1a;https://docs-multiplayer.unity3d.com/netcode/current/about/ Netcode for GameObjects&#xff08;NGO&#xff09;是专为Unity构建的高级网络库。它能够在网络会话中将GameObject和世界数据同时发…

计算机组成原理——基础入门总结(二)

上一期的路径&#xff1a;基础入门总结&#xff08;一&#xff09; 目录 一.输入输出系统和IO控制方式 二.存储系统的基本概念 三.cache的基本概念和原理 四.CPU的功能和基本结构 五.总线概述 一.输入输出系统和IO控制方式 IO设备又可以被统一称为外部设备~ IO接口&…

每日一题~修剪二叉树

原题链接&#xff1a;669. 修剪二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 思路分析&#xff1a; 由题可知&#xff0c;我们要将原来的二叉搜索树调整为值在 low~high 之间的新二叉搜索树&#xff0c;接下来我们分析一下针对不同的节点的处理方…

Hbase工作原理

Hbase&#xff1a;HBase 底层原理详解&#xff08;深度好文&#xff0c;建议收藏&#xff09; - 腾讯云开发者社区-腾讯云 Hbase架构图 同一个列族如果有多个store&#xff0c;那么这些store在不同的region Hbase写流程&#xff08;读比写慢&#xff09; MemStore Flush Hbas…

微信朋友圈的高级玩法

面对好友的生日&#xff0c;你还在傻傻的守点发朋友圈&#xff0c;节日庆祝你还在傻傻的守点官宣吗&#xff1f;还有你关注的那个他&#xff08;她&#xff09;&#xff0c;他&#xff08;她&#xff09;发的朋友圈你想成为第一个点赞评论的人吗&#xff1f;想和他进行更多的交…

如何自动获取短信验证码?

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ 这篇文章通过解决实际项目开发中遇到的如何自动获取短信验证码的问题&#xff0c;进一步讲述在Java中如何使用正则。 Java中如何使用正则 Java中正则相关类位于java.util.r…

python pytesseract 中文文字批量识别

用pytesseract 来批量把图片转成文字 1、安装好 pytesseract 包 2、下载安装OCR https://download.csdn.net/download/m0_37622302/88348824https://download.csdn.net/download/m0_37622302/88348824 Index of /tesseracthttps://digi.bib.uni-mannheim.de/tesseract/ 我是…

DevOps与CI/CD常见面试问题汇总

01 您能告诉我们DevOps和Agile(敏捷)之间的根本区别吗&#xff1f; 答&#xff1a;尽管DevOps与敏捷方法&#xff08;这是最流行的SDLC[Software Development Life Cycle]方法之一&#xff09;有一些相似之处&#xff0c;但两者在软件开发方面都是根本不同的方法。以下是两者之…

SpringCloud Gateway--网关服务基本介绍和基本原理

&#x1f600;前言 本篇博文是关于SpringCloud Gateway的基本介绍&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满意是我的动力…

【lesson8】操作系统的理解和类比

文章目录 操作系统是什么&#xff1f;为什么要有操作系统&#xff1f;怎么做&#xff1f;学校的例子&#xff08;理解管理&#xff09;银行的例子&#xff08;类比操作系统&#xff09; 操作系统是什么&#xff1f; 操作系统是一款软件&#xff0c;是为了进行软硬件资源管理的…

400电话怎么办理(申请开通)

申请开通400电话是一项相对简单的过程&#xff0c;只需按照以下步骤进行操作即可。 第一步&#xff0c;选择400电话服务提供商。在市场上有很多公司提供400电话服务&#xff0c;您可以根据自己的需求和预算选择适合的服务商。可以通过搜索引擎、咨询朋友或者查看相关论坛等方式…