diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/ClientConfig.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/ClientConfig.java
index da08592ec..6f2e8e99f 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/client/ClientConfig.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/ClientConfig.java
@@ -56,6 +56,10 @@ public class ClientConfig {
* 代理
*/
private HttpProxy proxy;
+ /**
+ * 是否遇到响应状态码3xx时自动重定向请求
+ */
+ private boolean followRedirects;
/**
* 构造
@@ -152,7 +156,7 @@ public class ClientConfig {
*
* @return this
*/
- public ClientConfig enableSSLVerify(){
+ public ClientConfig enableSSLVerify() {
return setSSLInfo(SSLInfo.DEFAULT);
}
@@ -204,4 +208,26 @@ public class ClientConfig {
this.proxy = proxy;
return this;
}
+
+ /**
+ * 是否遇到响应状态码3xx时自动重定向请求
+ * 注意:当打开客户端级别的自动重定向,则{@link Request#maxRedirectCount()}无效
+ *
+ * @return 是否遇到响应状态码3xx时自动重定向请求
+ */
+ public boolean isFollowRedirects() {
+ return followRedirects;
+ }
+
+ /**
+ * 设置是否遇到响应状态码3xx时自动重定向请求
+ * 注意:当打开客户端级别的自动重定向,则{@link Request#maxRedirectCount()}无效
+ *
+ * @param followRedirects 是否遇到响应状态码3xx时自动重定向请求
+ * @return this
+ */
+ public ClientConfig setFollowRedirects(final boolean followRedirects) {
+ this.followRedirects = followRedirects;
+ return this;
+ }
}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/Request.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/Request.java
index 420e21d6d..2b48866cc 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/client/Request.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/Request.java
@@ -293,6 +293,7 @@ public class Request implements HeaderOperation {
// endregion
// region body get
+
/**
* 获取请求体
*
@@ -343,6 +344,7 @@ public class Request implements HeaderOperation {
// endregion
// region body set
+
/**
* 添加请求表单内容
*
@@ -386,7 +388,7 @@ public class Request implements HeaderOperation {
if (StrUtil.isBlank(header(HeaderName.CONTENT_TYPE))) {
final String contentType = body.contentType(charset());
// 如果用户自定义的Header为null,不调用,防止实现类中可能的空指针问题
- if(null != contentType){
+ if (null != contentType) {
header(HeaderName.CONTENT_TYPE, contentType, true);
}
}
@@ -396,7 +398,8 @@ public class Request implements HeaderOperation {
// endregion
/**
- * 获取最大重定向请求次数
+ * 获取最大重定向请求次数
+ * 注意:当{@link ClientConfig#isFollowRedirects()}为{@code true}时,此参数无效
*
* @return 最大重定向请求次数
*/
@@ -406,7 +409,8 @@ public class Request implements HeaderOperation {
/**
* 设置最大重定向次数
- * 如果次数小于1则表示不重定向,大于等于1表示打开重定向
+ * 如果次数小于1则表示不重定向,大于等于1表示打开重定向
+ * 注意:当{@link ClientConfig#isFollowRedirects()}为{@code true}时,此参数无效
*
* @param maxRedirectCount 最大重定向次数
* @return this
@@ -477,13 +481,14 @@ public class Request implements HeaderOperation {
/**
* 检查form表单中的对象是否为Multipart对象
+ *
* @param value 对象
* @return 是否为Multipart对象
*/
- private static boolean hasMultipartValue(final Object value){
- if(value instanceof Iterable){
+ private static boolean hasMultipartValue(final Object value) {
+ if (value instanceof Iterable) {
for (final Object subValue : (Iterable>) value) {
- if(hasMultipartValue(subValue)){
+ if (hasMultipartValue(subValue)) {
return true;
}
}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/HttpClient4Engine.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/HttpClient4Engine.java
index b17c2641b..5fbd7c047 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/HttpClient4Engine.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/HttpClient4Engine.java
@@ -25,10 +25,7 @@ import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.client.BasicCredentialsProvider;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.dromara.hutool.core.io.IoUtil;
@@ -118,7 +115,7 @@ public class HttpClient4Engine extends AbstractClientEngine {
if (null != sslInfo) {
clientBuilder.setSSLSocketFactory(buildSocketFactory(sslInfo));
}
- if(config.isDisableCache()){
+ if (config.isDisableCache()) {
clientBuilder.disableAuthCaching();
}
@@ -128,8 +125,12 @@ public class HttpClient4Engine extends AbstractClientEngine {
// 设置默认头信息
clientBuilder.setDefaultHeaders(toHeaderList(GlobalHeaders.INSTANCE.headers()));
- // 默认关闭自动重定向
- clientBuilder.disableRedirectHandling();
+ // 重定向
+ if (config.isFollowRedirects()) {
+ clientBuilder.setRedirectStrategy(LaxRedirectStrategy.INSTANCE);
+ } else {
+ clientBuilder.disableRedirectHandling();
+ }
// 设置代理
setProxy(clientBuilder, config);
@@ -156,7 +157,7 @@ public class HttpClient4Engine extends AbstractClientEngine {
// 填充自定义消息体
final HttpBody body = message.handledBody();
- if(null != body){
+ if (null != body) {
requestBuilder.setEntity(new HttpClient4BodyEntity(
// 用户自定义的内容类型
message.header(HeaderName.CONTENT_TYPE),
@@ -194,6 +195,7 @@ public class HttpClient4Engine extends AbstractClientEngine {
/**
* 构建连接池管理器
+ *
* @param config 配置
* @return PoolingHttpClientConnectionManager
*/
@@ -201,7 +203,7 @@ public class HttpClient4Engine extends AbstractClientEngine {
final PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
// 连接池配置
- if(config instanceof HttpClientConfig){
+ if (config instanceof HttpClientConfig) {
final HttpClientConfig httpClientConfig = (HttpClientConfig) config;
manager.setMaxTotal(httpClientConfig.getMaxTotal());
manager.setDefaultMaxPerRoute(httpClientConfig.getMaxPerRoute());
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient5/HttpClient5Engine.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient5/HttpClient5Engine.java
index 62b0b62ba..da4540733 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient5/HttpClient5Engine.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient5/HttpClient5Engine.java
@@ -21,6 +21,7 @@ import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
@@ -119,15 +120,19 @@ public class HttpClient5Engine extends AbstractClientEngine {
final ClientConfig config = ObjUtil.defaultIfNull(this.config, HttpClientConfig::of);
clientBuilder.setConnectionManager(buildConnectionManager(config));
clientBuilder.setDefaultRequestConfig(buildRequestConfig(config));
- if(config.isDisableCache()){
+ if (config.isDisableCache()) {
clientBuilder.disableAuthCaching();
}
// 设置默认头信息
clientBuilder.setDefaultHeaders(toHeaderList(GlobalHeaders.INSTANCE.headers()));
- // 默认关闭自动重定向
- clientBuilder.disableRedirectHandling();
+ // 重定向
+ if (config.isFollowRedirects()) {
+ clientBuilder.setRedirectStrategy(DefaultRedirectStrategy.INSTANCE);
+ } else {
+ clientBuilder.disableRedirectHandling();
+ }
// 设置代理
setProxy(clientBuilder, config);
@@ -153,7 +158,7 @@ public class HttpClient5Engine extends AbstractClientEngine {
// 填充自定义消息体
final HttpBody body = message.handledBody();
- if(null != body){
+ if (null != body) {
request.setEntity(new HttpClient5BodyEntity(
// 用户自定义的内容类型
message.header(HeaderName.CONTENT_TYPE),
@@ -202,7 +207,7 @@ public class HttpClient5Engine extends AbstractClientEngine {
}
// 连接池配置
- if(config instanceof HttpClientConfig){
+ if (config instanceof HttpClientConfig) {
final HttpClientConfig httpClientConfig = (HttpClientConfig) config;
final int maxTotal = httpClientConfig.getMaxTotal();
final int maxPerRoute = httpClientConfig.getMaxPerRoute();
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/jdk/JdkClientEngine.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/jdk/JdkClientEngine.java
index 3ce4d139a..435d517c6 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/jdk/JdkClientEngine.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/jdk/JdkClientEngine.java
@@ -129,8 +129,8 @@ public class JdkClientEngine extends AbstractClientEngine {
.setReadTimeout(config.getReadTimeout())
.setMethod(message.method())//
.setSSLInfo(config.getSslInfo())
- // 关闭JDK自动转发,采用手动转发方式
- .setInstanceFollowRedirects(false)
+ // 如果客户端设置自动重定向,则Request中maxRedirectCount无效
+ .setInstanceFollowRedirects(config.isFollowRedirects())
.setDisableCache(config.isDisableCache())
// 覆盖默认Header
.header(message.headers(), true);
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/okhttp/OkHttpEngine.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/okhttp/OkHttpEngine.java
index bb803fea0..1a330adb4 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/okhttp/OkHttpEngine.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/okhttp/OkHttpEngine.java
@@ -129,8 +129,8 @@ public class OkHttpEngine extends AbstractClientEngine {
// 设置代理
setProxy(builder, config);
- // 默认关闭自动跳转
- builder.followRedirects(false);
+ // 重定向
+ builder.followRedirects(config.isFollowRedirects());
this.client = builder.build();
}