使用 Feign 客户端执行计划任务的 Spring Boot 应用程序中出现循环 HTTP 400 错误

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

我在使用 Feign 客户端进行服务间通信的 Spring Boot 应用程序中遇到循环错误模式。此问题特别出现在以一分钟间隔发出 HTTP POST 请求的计划任务中。观察到的行为明显是循环的:如果应用程序启动并且第一个计划请求返回 HTTP 400(错误请求),则该会话中的所有后续请求将继续返回 HTTP 400 错误。如果我终止进程并重新启动应用程序,行为就会相反 - 这次,所有请求都会成功,没有任何错误。每次重新启动应用程序时都会重复此模式:以错误启动的会话将始终出现错误,而正确启动的会话将始终正确运行。

这个周期性问题仍然存在,无需对服务器进行任何更改,服务器配置为一致地处理请求。

示例场景:

启动应用程序 - 第一个请求返回 HTTP 400。

此会话中的所有后续请求也返回 HTTP 400。

终止应用程序进程并重新启动。

这次重启后第一次请求就成功了。

此新会话中的所有后续请求均成功。

终止并重新启动进程,步骤 1 中的问题会重复。

这是我的通信中涉及的客户端和服务器代码的简化版本:

    @FeignClient(name = "withdraw-feign-client", url = "127.0.0.1:8081")
    public interface WithdrawFeignClient {
        @PostMapping("/withdraw/pullWithdraw")
        @ResponseBody
        CommonResult<List<WithdrawVO>> pullWithdraw(@RequestBody RequestData<PullWithdrawReq> req);
    }


    RequestData requestData = new RequestData();
    requestData.setChain(Chain.FIL);
    requestData.setDataString("123");
    requestData.setData(pullWithdrawReq);
    CommonResult<List<com.dhlfy.financerpcclient.WithdrawVO>> result =     withdrawFeignClient.pullWithdraw(requestData);


    @PostMapping("/pullWithdraw")
    public CommonResult<List<WithdrawVO>> pullWithdraw(@RequestBody RequestData<PullWithdrawReq> req) {
        String k = formatParma(req);
        PullWithdrawReq withdrawReq = JSONObject.parseObject(k, PullWithdrawReq.class);
        checkSign(withdrawReq);
        return CommonResult.success(withdrawService.pullWithdraw(req.getChain().name(), withdrawReq));
    }
java spring-mvc spring-cloud spring-cloud-feign
1个回答
0
投票

我遇到了几乎相同的问题,但面临完全相同的场景:使用 Feign 从计划任务中触发

POST
HTTP 请求。在我的例子中,唯一的区别是来自
@SpringBootTest
的 HTTP 调用将始终返回 200,而来自计划任务内的所有调用只会返回 400。

我在通过套接字发送数据之前放置了一个断点 (

L100: feign.SynchronousMethodHandler
) 并捕获了 2 个堆栈跟踪。比较它们,除了最开始的级别之外,调用堆栈似乎没有任何差异,这让我困惑了很长一段时间。

在那个阶段一无所知,然后我意识到我没有配置任何特定的客户端实现(Apache、OkHttp 等),因此我尝试在配置中指定一个并观察其行为。我使用了 OkHttp 和以下配置:

pom.xml

...
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.5</version>
    <relativePath/>
</parent>
...
<dependencies>
  ...
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
   </dependency>
   <dependency>
       <groupId>io.github.openfeign</groupId>
       <artifactId>feign-jackson</artifactId>
       <version>13.3</version>
   </dependency>
   <dependency>
       <groupId>org.jsoup</groupId>
       <artifactId>jsoup</artifactId>
       <version>1.18.3</version>
   </dependency>
   <dependency>
       <groupId>io.github.openfeign</groupId>
       <artifactId>feign-okhttp</artifactId>
   </dependency>
</dependencies>
...
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2023.0.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

HttpClientsConfig.java

package house.x1337.livefeed.config;

import feign.Client;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import okhttp3.OkHttpClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableFeignClients(basePackages = {
    "house.x1337.livefeed.client"
})
public class HttpClientsConfig {
    @Bean
    public Decoder decoder() {
        return new JacksonDecoder();
    }

    @Bean
    public Encoder encoder() {
        return new JacksonEncoder();
    }

    @Bean
    public Client client() {
        return new feign.okhttp.OkHttpClient(new OkHttpClient());
    }
}

然后一切就神奇地开始工作了。这是我见过的最奇怪的问题之一,因为我从未深入了解它。最初我认为这与自动配置生命周期或线程级上下文有关。在这两个区域调试了很多组件,但没有什么明显的。

值得一提的是,通过从请求中删除“Host”标头,我能够在 Postman 上按需重现 400。这是一个受限制的标头,应该由 JVM 在运行时隐式设置。这是 Feign 中的一个已知问题,如下所述:https://github.com/OpenFeign/feign/issues/747可能是,根据项目的配置,由于某种原因,此标头不会通过套接字发送。这是一个核心标头,大多数(如果不是所有)服务器都希望将请求适当地分派到下游,如果不存在,请求将被拒绝为无效。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.