Spring Boot中的Feign客户端:RequestParam.value()在第一个参数上为空

36
我创建了一个简单的Spring Boot Feign客户端,代码如下所示:

@FeignClient("spring-cloud-eureka-client")
public interface GreetingClient {
    @RequestMapping("/greeting")
    String greeting(@RequestParam String name);
}

但是当我尝试启动一个应用程序时,出现了错误:
java.lang.IllegalStateException: RequestParam.value() was empty on parameter 0

一开始我不明白原因,搜了很多但都没找到答案。差点忘记的是,只有为请求参数显式指定名称时才能正常工作:

@RequestParam("name") String name

所以我的问题是:这是一个 bug 吗,还是可以配置为不显式地写入请求参数名称?

1
我认为需要设置jvm,以便在Java 8中可以使用参数名称。 - spencergibb
@spencergibb 在同一JVM上,普通的Spring REST控制器无需任何额外的设置即可正常工作。 - Igorock
4个回答

43
Spring MVC和Spring Cloud Feign都使用同一个ParameterNameDiscoverer,名为DefaultParameterNameDiscoverer,以查找参数名称。它尝试按以下步骤查找参数名。
首先,它使用StandardReflectionParameterNameDiscoverer。它尝试使用反射找到变量名。当类使用-parameters编译时才可能实现此目的。
其次,如果失败,它会使用LocalVariableTableParameterNameDiscoverer。它尝试从类文件中的调试信息中使用ASM库找到变量名。
Spring MVC和Feign之间的区别在于这里。当我们使用Spring MVC时,我们在Java类的方法上使用上述注释(例如@RequestParam),而Feign则在Java接口的方法上使用注释。不幸的是,javac编译器会省略类文件中参数名称的调试信息,导致Feign无法在java接口中查找参数名称,除非使用-parameters。
换句话说,如果您使用-parameters编译代码,则Spring MVC和Feign都将成功获取参数名称。但是,如果没有使用-parameters进行编译,则只有Spring MVC能够成功。
因此,这不是一个错误。我认为这是Feign目前的限制。

1
一个小的补充是在“parameters”单词末尾加上“s”。 - Wizzard
Maven解决方案适用于Spring Boot 2:https://dev59.com/1I3da4cB1Zd3GeqP4svp - Robin Bruneel

33

只需使用String greeting(@RequestParam("name") String name);

    @FeignClient("spring-cloud-eureka-client")
    public interface GreetingClient {
       @RequestMapping("/greeting")
       String greeting(@RequestParam("name") String name);
    }

1
像魔法一样运作良好。 - ktcl
谢谢,这很有帮助。但是为什么需要添加@RequestParam("name")而不是@RequestParam?默认情况下应该会自动获取,对吧? - Mosa
1
@Mosa,请查看youngsung.yoon的答案。 - Jebil

1

这对我有用。

    @FeignClient(name="session-service", url="${session.host}")
    public interface SrocessingProxy {

    @RequestMapping(value = "/process/{key}", method = RequestMethod.POST)
    public Response processSession(@RequestParam String key, @RequestBody PayloadHolder payload);
    }
    
    //Service 
    @RequestMapping(value = "/process/{key}", method = RequestMethod.POST)
    public Response processSession(@RequestParam String key, @RequestBody PayloadHolder payload) { 
        System.out.print("Key : " + key);
    }

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接