java - 如何在 POST 请求中向其他 Feign 客户端发出 GET 请求?

标签 java spring spring-cloud

我有一个 REST API 端点,它利用多个 Fe​​ign 客户端来执行验证和处理。相关端点接受 POST 请求,但用于验证的 Feign 客户端接受 GET 请求。当我向 API 端点发出 POST 请求时,我从需要 GET 的 Feign 客户端收到以下错误。我的 Feign 客户端方法注释有 @GetMapping ,但请求似乎仍在以 POST 形式发送。如何在 POST 请求中向 Feign 客户端发出 GET 请求?

feign.FeignException: status 405 reading ValidationClient#checkData(String); content:
{"timestamp":"2018-08-06T14:43:45.998+0000","status":405,"error":"Method Not Allowed","message":"Request method 'POST' not supported","path":"/"}
    at feign.FeignException.errorStatus(FeignException.java:62) ~[feign-core-9.5.1.jar:na]
    at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:91) ~[feign-core-9.5.1.jar:na]
    at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:138) ~[feign-core-9.5.1.jar:na]
    at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76) ~[feign-core-9.5.1.jar:na]
    at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-9.5.1.jar:na]
    at com.sun.proxy.$Proxy129.checkFormat(Unknown Source) ~[na:na]
    at com.example.datainput.DataInputController.acceptData(DataInputController.java:20) ~[classes/:na]
    at sun.reflect.GeneratedMethodAccessor126.invoke(Unknown Source) ~[na:na]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:45005) ~[na:1.8.0_172]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_172]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) ~[spring-webmvc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) ~[spring-webmvc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) ~[spring-webmvc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877) ~[spring-webmvc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851) ~[spring-webmvc-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:40002) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_172]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_172]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.32.jar:8.5.32]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_172]

编辑:

假客户端

@FeignClient("validation")
public interface ValidationClient {

    @GetMapping("/")
    boolean checkFormat(String data);

}

客户端的 Controller

@RestController
public class ValidationController {

    @Autowired
    ValidationProperties properties;

    @GetMapping("/")
    public boolean isValidFormat(@RequestParam String inputData) {
        return inputData.matches(properties.getValidFormat());
    }

}

使用客户端的 REST 端点

@RestController
public class DataInputController {

    @Autowired
    ValidationClient validationClient;

    @PostMapping("/")
    public String saveData(@RequestParam(name = "inputData") String inputData) {

        if (!validationClient.checkFormat(inputData)) {
            return "Invalid Format";
        }

        // save data here

        return "Input Success";
    }

}

我使用的是FINCHLEY.SR1版本

编辑2:

我注意到 Controller 中的 Feign 客户端似乎配置错​​误。 它们的类型为 HardCodedTarget url 属性只是 http://<service-name> (在本例中 http://validation ),它实际上并不指向客户端应该使用的真实服务。

编辑3: 我添加了功能区

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

到我的服务应用程序和我使用 Feign 客户端的 api。不幸的是我仍然遇到同样的问题。我已经刷新并重建了一切。

编辑4: 我为这个问题创建了一个 GitHub 项目。

https://github.com/zero01alpha/spring-cloud-demo

input-entry 模块使用 input-format 和 input-parse 模块作为 Feign 客户端来验证输入字符串的长度和解析/打印项。我一直使用字母表作为输入,因此输入参数的最小长度设置为 26。 input-format 在端口 8080 上运行,input-parse 在 8081 上运行,input-entry 在 8082 上运行,所有这些都使用默认路径 /作为它们唯一的端点,并且需要名为 input 的请求参数。因此,为了重现我遇到的问题

  1. 启动配置服务器
  2. 启动 Eureka 服务器
  3. 启动输入格式服务
  4. 启动输入解析服务
  5. 启动输入录入服务

然后,发送 POST 请求至 localhost:8082请求参数为input至少有 26 个字符。当我这样做时,我会得到这个响应正文。

{
    "timestamp": "2018-08-09T13:29:34.536+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "status 405 reading InputFormatClient#checkFormat(String); content:\n{\"timestamp\":\"2018-08-09T13:29:34.504+0000\",\"status\":405,\"error\":\"Method Not Allowed\",\"message\":\"Request method 'POST' not supported\",\"path\":\"/\"}",
    "path": "/"
}

最佳答案

默认情况下,feign 方法的任何参数都被视为正文,因此您的 checkFormat() 方法将发送一个帖子,因为它有一个正文(get 不能)。所以这个:

@FeignClient("input-format")
public interface InputFormatClient {

    @GetMapping("/")
    boolean checkFormat(String input);

}

需要:

@FeignClient("input-format")
public interface InputFormatClient {

    @GetMapping("/")
    boolean checkFormat(@RequestParam("input") String input);

}

其他客户端也需要进行类似的更新

@FeignClient("input-parse")
public interface InputParseClient {

    @GetMapping("/")
    Map<String, String> getParsedItems(@RequestParam("input") String input);

}

关于java - 如何在 POST 请求中向其他 Feign 客户端发出 GET 请求?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51711348/

相关文章:

spring-security - 使用 Spring Cloud Config 进行外部日志配置

java - Maven : Get the root path of the parent project in the child project

java - 在 java 中执行 sql 查询时避免 ORA-00904 - 无效标识符错误,因为该列可能会也可能不会在数据库中预设

java - 如何模拟 bean 的某些方法调用,但在同一测试类中的其他方法调用中使用定义的 bean?

spring - 在我的 Spring 批处理中添加 maven 依赖项会出现特定错误

spring-cloud - Spring Cloud : Canary Deployments with Zuul

java.io.EOFException : End of input at line 1 column 1 path $ in Android retrofit 异常

java - org.apache.solr.common.SolrException : undefined field name

java - activiti 6 中表达中使用的未知方法

java - 为什么 Spring Cloud Consul 不能与独立的 Tomcat 一起使用?