You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自定义OpenFeign实现带请求体的POST请求重定向?

解决OpenFeign带请求体POST请求302重定向失败问题

问题描述

使用OpenFeign发送带请求体的POST请求到返回HTTP 302状态码的服务器时,会抛出HttpRetryException: cannot retry due to redirection, in streaming mode错误;但POST请求不带请求体时,Feign可正常跟随重定向。该问题由sun.net.www.protocol.http.HttpURLConnection的限制导致,它默认阻止带请求体的POST请求执行重定向。

解决方案

1. 替换默认HttpClient为Apache HttpClient或OkHttp

Feign默认使用JDK的HttpURLConnection,可替换为支持带请求体重定向的第三方客户端:

以Apache HttpClient为例:

首先引入Maven依赖:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
    <version>对应Feign版本</version>
</dependency>

修改Feign配置,使用ApacheHttpClient:

@Configuration
public class FeignConfiguration {
    @Bean
    public FeignPostRedirectClient feignPostRedirectClient() {
        return Feign.builder()
                .logLevel(Logger.Level.FULL)
                .logger(new Slf4jLogger())
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .client(new ApacheHttpClient()) // 替换为Apache HttpClient
                .options(new Request.Options(10, TimeUnit.SECONDS, 10, TimeUnit.SECONDS, true))
                .target(FeignPostRedirectClient.class, "http://localhost:8082");
    }
}

Apache HttpClient默认支持处理带请求体的POST重定向,会按HTTP规范自动处理请求方法转换(跨域重定向时POST转GET,同域则保持POST),也可自定义配置。

2. 自定义Feign Client手动处理重定向

若不想替换HttpClient,可自定义Feign Client捕获302状态码,手动重新发送请求:

public class CustomFeignClient implements Client {
    private final Client delegate;

    public CustomFeignClient(Client delegate) {
        this.delegate = delegate;
    }

    @Override
    public Response execute(Request request, Request.Options options) throws IOException {
        Response response = delegate.execute(request, options);
        // 处理302重定向
        if (response.status() == 302) {
            String location = response.headers().get("Location").iterator().next();
            // 构建新请求,可根据业务需求选择保持POST或转为GET
            Request newRequest = Request.create(request.method(), location, request.headers(), request.body(), request.charset());
            return delegate.execute(newRequest, options);
        }
        return response;
    }
}

在Feign配置中使用该自定义Client:

@Configuration
public class FeignConfiguration {
    @Bean
    public FeignPostRedirectClient feignPostRedirectClient() {
        Client defaultClient = new Client.Default(null, null);
        return Feign.builder()
                .logLevel(Logger.Level.FULL)
                .logger(new Slf4jLogger())
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .client(new CustomFeignClient(defaultClient)) // 使用自定义Client
                .options(new Request.Options(10, TimeUnit.SECONDS, 10, TimeUnit.SECONDS, true))
                .target(FeignPostRedirectClient.class, "http://localhost:8082");
    }
}

注意:手动处理时需遵循HTTP规范,RFC规定跨域POST重定向应转为GET,若业务需保持POST可自定义逻辑。

3. 调整服务器端重定向逻辑(若可控)

若有权限修改服务器,可将302改为307或308状态码:

  • 307:临时重定向,强制保持原请求方法和请求体
  • 308:永久重定向,强制保持原请求方法和请求体
    JDK的HttpURLConnection支持这两个状态码的重定向,不会抛出上述错误。

原问题相关代码

Feign客户端接口

public interface FeignPostRedirectClient {
  @RequestLine("POST /redirect-server")
  void sendPostRequestWithBodyToRedirectServer(Map<String, ?> formBodyParams);  // 重定向失败
  //void sendPostRequestWithBodyToRedirectServer();  // 重定向成功
}

Feign配置类

@Configuration
public class FeignConfiguration {
    @Bean
    public FeignPostRedirectClient feignPostRedirectClient() {
        return Feign.builder()
                .logLevel(Logger.Level.FULL)
                .logger(new Slf4jLogger())
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .options(new Request.Options(10, TimeUnit.SECONDS, 10, TimeUnit.SECONDS, true))
                .target(FeignPostRedirectClient.class, "http://localhost:8082");
    }
}

调用代码

Map<String, String> formParams = new HashMap<>();
formParams.put("Username", "alice");
formParams.put("Password", "pass");
feignPostRedirectClient.sendPostRequestWithBodyToRedirectServer(formParams);

错误日志

2022-11-21 21:53:49.880 DEBUG 3944 --- [ main] feign.Logger
: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
---> POST http://localhost:8082/redirect-server HTTP/1.1 2022-11-21 21:53:49.880 DEBUG 3944 --- [ main] feign.Logger

: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
Content-Length: 49 2022-11-21 21:53:49.880 DEBUG 3944 --- [

main] feign.Logger :
[FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
2022-11-21 21:53:49.880 DEBUG 3944 --- [ main] feign.Logger
: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer] {
"Username" : "alice", "Password" : "pass" } 2022-11-21 21:53:49.881
DEBUG 3944 --- [ main] feign.Logger

: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
---> END HTTP (49-byte body) 2022-11-21 21:53:54.368 DEBUG 3944 --- [ main] feign.Logger :
[FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer] <---
ERROR HttpRetryException: cannot retry due to redirection, in
streaming mode (4485ms) 2022-11-21 21:53:54.371 DEBUG 3944 --- [

main] feign.Logger :
[FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
java.net.HttpRetryException: cannot retry due to redirection, in
streaming mode at
sun.net.www.protocol.http.HttpURLConnection.followRedirect0(HttpURLConnection.java:2682)
at
sun.net.www.protocol.http.HttpURLConnection.followRedirect(HttpURLConnection.java:2668)
at
sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1847)
at
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1505)
at
java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at feign.Client$Default.convertResponse(Client.java:110) at
feign.Client$Default.execute(Client.java:106) at
feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:102)
at
feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:72)
at
feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:109)
at
com.sun.proxy.$Proxy71.sendPostRequestWithBodyToRedirectServer(Unknown
Source) at
com.kingsoo.online.store.service.OnlineStoreServiceApplication.run(OnlineStoreServiceApplication.java:28)
at
org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:771)
at
org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:755)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)
at
com.kingsoo.online.store.service.OnlineStoreServiceApplication.main(OnlineStoreServiceApplication.java:19)

2022-11-21 21:53:54.371 DEBUG 3944 --- [ main] feign.Logger
: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
<--- END ERROR 2022-11-21 21:53:54.588 DEBUG 3944 --- [

main] feign.Logger :
[FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer] --->
RETRYING 2022-11-21 21:53:54.589 DEBUG 3944 --- [ main]
feign.Logger :
[FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer] --->
POST http://localhost:8082/redirect-server HTTP/1.1 2022-11-21
21:53:54.591 DEBUG 3944 --- [ main] feign.Logger

: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
Content-Length: 49 2022-11-21 21:53:54.591 DEBUG 3944 --- [

main] feign.Logger :
[FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
2022-11-21 21:53:54.592 DEBUG 3944 --- [ main] feign.Logger
: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer] {
"Username" : "alice", "Password" : "pass" } 2022-11-21 21:53:54.592
DEBUG 3944 --- [ main] feign.Logger

: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
---> END HTTP (49-byte body) 2022-11-21 21:54:54.606 DEBUG 3944 --- [ main] feign.Logger :
[FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer] <---
ERROR SocketTimeoutException: Read timed out (60010ms) 2022-11-21
21:54:54.609 DEBUG 3944 --- [ main] feign.Logger

: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
java.net.SocketTimeoutException: Read timed out at
java.net.SocketInputStream.socketRead0(Native Method) at
java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at
java.net.SocketInputStream.read(SocketInputStream.java:171) at
java.net.SocketInputStream.read(SocketInputStream.java:141) at
java.io.BufferedInputStream.fill(BufferedInputStream.java:246) at
java.io.BufferedInputStream.read1(BufferedInputStream.java:286) at
java.io.BufferedInputStream.read(BufferedInputStream.java:345) at
sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:743) at
sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678) at
sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1600)
at
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1505)
at
java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at feign.Client$Default.convertResponse(Client.java:110) at
feign.Client$Default.execute(Client.java:106) at
feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:102)
at
feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:72)
at
feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:109)
at
com.sun.proxy.$Proxy71.sendPostRequestWithBodyToRedirectServer(Unknown
Source) at
com.kingsoo.online.store.service.OnlineStoreServiceApplication.run(OnlineStoreServiceApplication.java:28)
at
org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:771)
at
org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:755)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)
at
com.kingsoo.online.store.service.OnlineStoreServiceApplication.main(OnlineStoreServiceApplication.java:19)

2022-11-21 21:54:54.609 DEBUG 3944 --- [ main] feign.Logger
: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
<--- END ERROR 2022-11-21 21:54:54.840 DEBUG 3944 --- [

main] feign.Logger :
[FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer] --->
RETRYING 2022-11-21 21:54:54.842 DEBUG 3944 --- [ main]
feign.Logger :
[FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer] --->
POST http://localhost:8082/redirect-server HTTP/1.1 2022-11-21
21:54:54.842 DEBUG 3944 --- [ main] feign.Logger

: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
Content-Length: 49 2022-11-21 21:54:54.842 DEBUG 3944 --- [

main] feign.Logger :
[FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
2022-11-21 21:54:54.842 DEBUG 3944 --- [ main] feign.Logger
: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer] {
"Username" : "alice", "Password" : "pass" } 2022-11-21 21:54:54.842
DEBUG 3944 --- [ main] feign.Logger

: [FeignPostRedirectClient#sendPostRequestWithBodyToRedirectServer]
---> END HTTP (49-byte body)

内容的提问来源于stack exchange,提问作者user1726366

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 07:05:26