Spring Boot OpenFeign:java.lang.IllegalStateException:方法具有太多的Body参数

问题描述 投票:0回答:1

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

示例1使用HTTP.POST,其响应对象与示例2使用HTTP.GET。

为什么OpenFeign限制HTTP.GET方法中的字段,并引发异常?我无法使用HTTP.POST来获取/获取/读取资源。 BAD 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);
}

StackTrace:

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个回答
0
投票

根据标签,您正在使用Spring Boot,显然是通过Spring Cloud OpenFeign使用的。事实是,您要混合两个不同的伪装合同。

@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库,则可以使用它们(核心伪装是其组成部分之一)。该库带来了对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();
}
© www.soinside.com 2019 - 2024. All rights reserved.