Skip to content

Commit f651030

Browse files
committed
Align HttpClient defaults with Spring Framework and provide an opt-out
Update default for `ReactorClientHttpRequestFactoryBuilder` and `ReactorClientHttpConnectorBuilder` to align with Spring Framework. Also provide method of opting out in case proxyWithSystemProperties is not wanted. Closes gh-49950
1 parent d5aa685 commit f651030

5 files changed

Lines changed: 133 additions & 12 deletions

File tree

module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/ReactorClientHttpRequestFactoryBuilder.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,29 @@ public ReactorClientHttpRequestFactoryBuilder withHttpClientFactory(Supplier<Htt
9696
this.httpClientBuilder.withHttpClientFactory(factory));
9797
}
9898

99+
/**
100+
* Return a new {@link ReactorClientHttpRequestFactoryBuilder} that does not apply any
101+
* defaults when first creating the {@link HttpClient}.
102+
* @return a new {@link ReactorClientHttpRequestFactoryBuilder} instance
103+
* @since 4.1.0
104+
*/
105+
public ReactorClientHttpRequestFactoryBuilder withoutHttpClientDefaults() {
106+
return withHttpClientDefaults(null);
107+
}
108+
109+
/**
110+
* Return a new {@link ReactorClientHttpRequestFactoryBuilder} that applies the given
111+
* factory defaults when first creating the {@link HttpClient}.
112+
* @param factoryDefaults the factory to use
113+
* @return a new {@link ReactorClientHttpRequestFactoryBuilder} instance
114+
* @since 4.1.0
115+
*/
116+
public ReactorClientHttpRequestFactoryBuilder withHttpClientDefaults(
117+
@Nullable UnaryOperator<HttpClient> factoryDefaults) {
118+
return new ReactorClientHttpRequestFactoryBuilder(getCustomizers(),
119+
this.httpClientBuilder.withHttpClientDefaults(factoryDefaults));
120+
}
121+
99122
/**
100123
* Return a new {@link ReactorClientHttpRequestFactoryBuilder} that applies additional
101124
* customization to the underlying {@link HttpClient}.

module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/ReactorHttpClientBuilder.java

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,21 @@ public final class ReactorHttpClientBuilder {
5050

5151
private final Supplier<HttpClient> factory;
5252

53+
private final UnaryOperator<HttpClient> factoryDefaults;
54+
5355
private final UnaryOperator<HttpClient> customizer;
5456

5557
private final @Nullable ResolvedAddressSelector<? super HttpClientConfig> resolvedAddressSelector;
5658

5759
public ReactorHttpClientBuilder() {
58-
this(HttpClient::create, UnaryOperator.identity(), null);
60+
this(HttpClient::create, ReactorHttpClientBuilder::applySpringDefaults, UnaryOperator.identity(), null);
5961
}
6062

61-
private ReactorHttpClientBuilder(Supplier<HttpClient> httpClientFactory, UnaryOperator<HttpClient> customizer,
63+
private ReactorHttpClientBuilder(Supplier<HttpClient> factory, UnaryOperator<HttpClient> factoryDefaults,
64+
UnaryOperator<HttpClient> customizer,
6265
@Nullable ResolvedAddressSelector<? super HttpClientConfig> resolvedAddressSelector) {
63-
this.factory = httpClientFactory;
66+
this.factory = factory;
67+
this.factoryDefaults = factoryDefaults;
6468
this.customizer = customizer;
6569
this.resolvedAddressSelector = resolvedAddressSelector;
6670
}
@@ -74,6 +78,7 @@ private ReactorHttpClientBuilder(Supplier<HttpClient> httpClientFactory, UnaryOp
7478
public ReactorHttpClientBuilder withReactorResourceFactory(ReactorResourceFactory reactorResourceFactory) {
7579
Assert.notNull(reactorResourceFactory, "'reactorResourceFactory' must not be null");
7680
return new ReactorHttpClientBuilder(() -> HttpClient.create(reactorResourceFactory.getConnectionProvider()),
81+
this.factoryDefaults,
7782
(httpClient) -> this.customizer.apply(httpClient).runOn(reactorResourceFactory.getLoopResources()),
7883
this.resolvedAddressSelector);
7984
}
@@ -86,7 +91,31 @@ public ReactorHttpClientBuilder withReactorResourceFactory(ReactorResourceFactor
8691
*/
8792
public ReactorHttpClientBuilder withHttpClientFactory(Supplier<HttpClient> factory) {
8893
Assert.notNull(factory, "'factory' must not be null");
89-
return new ReactorHttpClientBuilder(factory, this.customizer, this.resolvedAddressSelector);
94+
return new ReactorHttpClientBuilder(factory, this.factoryDefaults, this.customizer,
95+
this.resolvedAddressSelector);
96+
}
97+
98+
/**
99+
* Return a new {@link ReactorHttpClientBuilder} that does not apply any defaults when
100+
* first creating the {@link HttpClient}.
101+
* @return a new {@link ReactorHttpClientBuilder} instance
102+
* @since 4.1.0
103+
*/
104+
public ReactorHttpClientBuilder withoutHttpClientDefaults() {
105+
return withHttpClientDefaults(null);
106+
}
107+
108+
/**
109+
* Return a new {@link ReactorHttpClientBuilder} that applies the given factory
110+
* defaults when first creating the {@link HttpClient}.
111+
* @param factoryDefaults the factory to use
112+
* @return a new {@link ReactorHttpClientBuilder} instance
113+
* @since 4.1.0
114+
*/
115+
public ReactorHttpClientBuilder withHttpClientDefaults(@Nullable UnaryOperator<HttpClient> factoryDefaults) {
116+
return new ReactorHttpClientBuilder(this.factory,
117+
(factoryDefaults != null) ? factoryDefaults : UnaryOperator.identity(), this.customizer,
118+
this.resolvedAddressSelector);
90119
}
91120

92121
/**
@@ -97,7 +126,7 @@ public ReactorHttpClientBuilder withHttpClientFactory(Supplier<HttpClient> facto
97126
*/
98127
public ReactorHttpClientBuilder withHttpClientCustomizer(UnaryOperator<HttpClient> customizer) {
99128
Assert.notNull(customizer, "'customizer' must not be null");
100-
return new ReactorHttpClientBuilder(this.factory,
129+
return new ReactorHttpClientBuilder(this.factory, this.factoryDefaults,
101130
(httpClient) -> customizer.apply(this.customizer.apply(httpClient)), this.resolvedAddressSelector);
102131
}
103132

@@ -112,7 +141,8 @@ public ReactorHttpClientBuilder withHttpClientCustomizer(UnaryOperator<HttpClien
112141
public ReactorHttpClientBuilder withResolvedAddressSelector(
113142
ResolvedAddressSelector<? super HttpClientConfig> resolvedAddressSelector) {
114143
Assert.notNull(resolvedAddressSelector, "'resolvedAddressSelector' must not be null");
115-
return new ReactorHttpClientBuilder(this.factory, this.customizer, resolvedAddressSelector);
144+
return new ReactorHttpClientBuilder(this.factory, this.factoryDefaults, this.customizer,
145+
resolvedAddressSelector);
116146
}
117147

118148
/**
@@ -122,7 +152,7 @@ public ReactorHttpClientBuilder withResolvedAddressSelector(
122152
*/
123153
public HttpClient build(@Nullable HttpClientSettings settings) {
124154
settings = (settings != null) ? settings : HttpClientSettings.defaults();
125-
HttpClient httpClient = applyDefaults(this.factory.get());
155+
HttpClient httpClient = this.factoryDefaults.apply(this.factory.get());
126156
PropertyMapper map = PropertyMapper.get();
127157
httpClient = map.from(settings::connectTimeout).to(httpClient, this::setConnectTimeout);
128158
httpClient = map.from(settings::readTimeout).to(httpClient, HttpClient::responseTimeout);
@@ -146,11 +176,6 @@ public HttpClient build(@Nullable HttpClientSettings settings) {
146176
: this.resolvedAddressSelector;
147177
}
148178

149-
HttpClient applyDefaults(HttpClient httpClient) {
150-
// Aligns with Spring Framework defaults
151-
return httpClient.compress(true);
152-
}
153-
154179
private HttpClient setConnectTimeout(HttpClient httpClient, Duration timeout) {
155180
return httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) timeout.toMillis());
156181
}
@@ -177,4 +202,9 @@ private void configureSsl(SslContextSpec spec, SslBundle sslBundle) throws SSLEx
177202
spec.sslContext(builder.build());
178203
}
179204

205+
static HttpClient applySpringDefaults(HttpClient httpClient) {
206+
// Aligns with Spring Framework defaults in ReactorClientHttpRequestFactory
207+
return httpClient.compress(true).proxyWithSystemProperties();
208+
}
209+
180210
}

module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/reactive/ReactorClientHttpConnectorBuilder.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,29 @@ public ReactorClientHttpConnectorBuilder withHttpClientFactory(Supplier<HttpClie
9090
this.httpClientBuilder.withHttpClientFactory(factory));
9191
}
9292

93+
/**
94+
* Return a new {@link ReactorClientHttpConnectorBuilder} that does not apply any
95+
* defaults when first creating the {@link HttpClient}.
96+
* @return a new {@link ReactorClientHttpConnectorBuilder} instance
97+
* @since 4.1.0
98+
*/
99+
public ReactorClientHttpConnectorBuilder withoutHttpClientDefaults() {
100+
return withHttpClientDefaults(null);
101+
}
102+
103+
/**
104+
* Return a new {@link ReactorClientHttpConnectorBuilder} that applies the given
105+
* factory defaults when first creating the {@link HttpClient}.
106+
* @param factoryDefaults the factory to use
107+
* @return a new {@link ReactorClientHttpConnectorBuilder} instance
108+
* @since 4.1.0
109+
*/
110+
public ReactorClientHttpConnectorBuilder withHttpClientDefaults(
111+
@Nullable UnaryOperator<HttpClient> factoryDefaults) {
112+
return new ReactorClientHttpConnectorBuilder(getCustomizers(),
113+
this.httpClientBuilder.withHttpClientDefaults(factoryDefaults));
114+
}
115+
93116
/**
94117
* Return a new {@link ReactorClientHttpConnectorBuilder} that applies additional
95118
* customization to the underlying {@link HttpClient}.

module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/ReactorClientHttpRequestFactoryBuilderTests.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.junit.jupiter.params.provider.EnumSource;
2929
import reactor.netty.http.client.HttpClient;
3030

31+
import org.springframework.http.client.ClientHttpRequestFactory;
3132
import org.springframework.http.client.ReactorClientHttpRequestFactory;
3233
import org.springframework.http.client.ReactorResourceFactory;
3334
import org.springframework.test.util.ReflectionTestUtils;
@@ -63,6 +64,29 @@ void withHttpClientFactory() {
6364
assertThat(called).containsExactly(true);
6465
}
6566

67+
@Test
68+
void springHttpClientDefaults() {
69+
ClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.reactor().build();
70+
assertThat(factory).extracting("httpClient.config.acceptGzip").isEqualTo(true);
71+
}
72+
73+
@Test
74+
void withoutHttpClientDefaults() {
75+
ClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.reactor()
76+
.withoutHttpClientDefaults()
77+
.build();
78+
assertThat(factory).extracting("httpClient.config.acceptGzip").isEqualTo(false);
79+
}
80+
81+
@Test
82+
void withHttpClientDefaults() {
83+
ClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.reactor()
84+
.withHttpClientDefaults((httpClient) -> httpClient.baseUrl("test"))
85+
.build();
86+
assertThat(factory).extracting("httpClient.config.acceptGzip").isEqualTo(false);
87+
assertThat(factory).extracting("httpClient.config.baseUrl").isEqualTo("test");
88+
}
89+
6690
@Test
6791
void withReactorResourceFactory() {
6892
ReactorResourceFactory resourceFactory = spy(new ReactorResourceFactory());

module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/reactive/ReactorClientHttpConnectorBuilderTests.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,27 @@ void withHttpClientFactory() {
6464
assertThat(called).containsExactly(true);
6565
}
6666

67+
@Test
68+
void springHttpClientDefaults() {
69+
ReactorClientHttpConnector connector = ClientHttpConnectorBuilder.reactor().build();
70+
assertThat(connector).extracting("httpClient.config.acceptGzip").isEqualTo(true);
71+
}
72+
73+
@Test
74+
void withoutHttpClientDefaults() {
75+
ReactorClientHttpConnector connector = ClientHttpConnectorBuilder.reactor().withoutHttpClientDefaults().build();
76+
assertThat(connector).extracting("httpClient.config.acceptGzip").isEqualTo(false);
77+
}
78+
79+
@Test
80+
void withHttpClientDefaults() {
81+
ReactorClientHttpConnector connector = ClientHttpConnectorBuilder.reactor()
82+
.withHttpClientDefaults((httpClient) -> httpClient.baseUrl("test"))
83+
.build();
84+
assertThat(connector).extracting("httpClient.config.acceptGzip").isEqualTo(false);
85+
assertThat(connector).extracting("httpClient.config.baseUrl").isEqualTo("test");
86+
}
87+
6788
@Test
6889
void withReactorResourceFactory() {
6990
ReactorResourceFactory resourceFactory = spy(new ReactorResourceFactory());

0 commit comments

Comments
 (0)