【问题标题】:Spring Boot OpenFeign: java.lang.IllegalStateException: Method has too many Body parametersSpring Boot OpenFeign: java.lang.IllegalStateException: Method has too many Body parameters
【发布时间】:2020-05-29 23:04:47
【问题描述】:

以下示例演示了使用 OpenFeign 时遇到的问题。当您的响应对象有太多字段时,问题就变得很明显,这会引发错误:方法有太多参数。示例 1 完美运行,但示例 2 失败。

示例 1 使用 HTTP.POST 和示例 2 中使用的相同响应对象,后者使用 HTTP.GET。

为什么OpenFeign会限制HTTP.GET方法中的字段,并抛出异常?我不能使用 HTTP.POST 来获取/获取/读取资源。糟糕的 REST API 设计标准。

使用相同的响应对象,对于 HTTP.POST(有效),HTTP.GET 失败

public interface ClientFeignV2 {

//Example 1 
@Headers("Content-Type: application/json") @RequestLine("POST api/v2/clients") ClientResponse findAllClientsByUid1(@RequestBody ClientRequest request);

//Example 2
@Headers("Content-Type: application/json")
@RequestLine("GET api/v2/clients/{uid}")
ClientResponse findAllClientsByUid(@PathVariable(value = "uid") String uid,
                                         @RequestParam(value = "limit", required = false) Integer limit,
                                         @RequestParam(value = "offset", required = false) Integer offset);
}

堆栈跟踪:

Caused by: java.lang.IllegalStateException: Method has too many Body parameters: public abstract com.services.requestresponse.ClientResponse com.microservice.gateway.feign.v2.ClientFeignV2.findAllClientsByUid(java.lang.String,java.lang.Integer,java.lang.Integer)
at feign.Util.checkState(Util.java:128) ~[feign-core-9.4.0.jar:na]
at feign.Contract$BaseContract.parseAndValidateMetadata(Contract.java:114) ~[feign-core-9.4.0.jar:na]
at feign.Contract$BaseContract.parseAndValidatateMetadata(Contract.java:64) ~[feign-core-9.4.0.jar:na]
at feign.ReflectiveFeign$ParseHandlersByName.apply(ReflectiveFeign.java:146) ~[feign-core-9.4.0.jar:na]
at feign.ReflectiveFeign.newInstance(ReflectiveFeign.java:53) ~[feign-core-9.4.0.jar:na]
at feign.Feign$Builder.target(Feign.java:209) ~[feign-core-9.4.0.jar:na]
at feign.Feign$Builder.target(Feign.java:205) ~[feign-core-9.4.0.jar:na]
at com.microservice.gateway.service.v2.impl.ClientServiceV2Impl.<init>(ClientServiceV2Impl.java:27) ~[classes/:na]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_222]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_222]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_222]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_222]
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:203) ~[spring-beans-5.2.3.RELEASE.jar:5.2.3.RELEASE]
... 40 common frames omitted

我浏览了 OpenFeign 文档,它支持上述实现。如果我找不到这个问题的解决方案,我将不得不求助于解决方法并使用 HTTP.POST@RequestBody,根据 Rest-API 设计标准,这不是理想的解决方案。

【问题讨论】:

    标签: java spring-boot http-get feign openfeign


    【解决方案1】:

    根据标签,您使用的是 Spring Boot,显然是使用 Spring Cloud OpenFeign。问题是你混合了两个不同的 Feign 合约。

    @RequestLine@Headers 等注解来自 core feign library。 您可以将其用作声明式 HTTP 客户端,而不仅仅是在 Spring 应用程序中(在这种情况下,它不需要使用 Spring 注释)。

    因此,使用普通 Feign 的正确“示例 2”可能是:

    @Headers("Content-Type: application/json")
    @RequestLine("GET api/v2/clients/{uid}?limit={limit}&offset={offset}")
    ClientResponse findAllClientsByUid(@Param("uid") String uid,
                                       @Param("limit") Integer limit,
                                       @Param("offset") Integer offset);
    

    另一方面,@RequestParam@PathVariable 之类的东西来自 Spring Web。 如果您有 Spring Cloud OpenFeign 库(顺便说一句,核心 feign 是其组件之一),则可以使用它们。 这个库带来了对SpringMvcContract 的支持,在这种情况下,它允许您使用通常的 Spring Web 注释来定义请求映射,而不是 Feign 特定的。

    如果是SpringMvcContract,“示例 2”可能是:

    @GetMapping(value = "api/v2/clients/{uid}", consumes = MediaType.APPLICATION_JSON_VALUE)
    ClientResponse findAllClientsByUid(@PathVariable(value = "uid") String uid,
                    @RequestParam(value = "limit", required = false) Integer limit,
                    @RequestParam(value = "offset", required = false) Integer offset);
    

    值得一提的是Spring Cloud OpenFeign the second approach is used by default。要将其改回普通的 Feign 合约,请定义自定义 Contract bean (source):

    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-16
      相关资源
      最近更新 更多