mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-10-06 09:19:19 +00:00
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
This commit is contained in:
+23
@@ -96,6 +96,29 @@ public final class ReactorClientHttpRequestFactoryBuilder
|
||||
this.httpClientBuilder.withHttpClientFactory(factory));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ReactorClientHttpRequestFactoryBuilder} that does not apply any
|
||||
* defaults when first creating the {@link HttpClient}.
|
||||
* @return a new {@link ReactorClientHttpRequestFactoryBuilder} instance
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public ReactorClientHttpRequestFactoryBuilder withoutHttpClientDefaults() {
|
||||
return withHttpClientDefaults(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ReactorClientHttpRequestFactoryBuilder} that applies the given
|
||||
* factory defaults when first creating the {@link HttpClient}.
|
||||
* @param factoryDefaults the factory to use
|
||||
* @return a new {@link ReactorClientHttpRequestFactoryBuilder} instance
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public ReactorClientHttpRequestFactoryBuilder withHttpClientDefaults(
|
||||
@Nullable UnaryOperator<HttpClient> factoryDefaults) {
|
||||
return new ReactorClientHttpRequestFactoryBuilder(getCustomizers(),
|
||||
this.httpClientBuilder.withHttpClientDefaults(factoryDefaults));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ReactorClientHttpRequestFactoryBuilder} that applies additional
|
||||
* customization to the underlying {@link HttpClient}.
|
||||
|
||||
+42
-12
@@ -50,17 +50,21 @@ public final class ReactorHttpClientBuilder {
|
||||
|
||||
private final Supplier<HttpClient> factory;
|
||||
|
||||
private final UnaryOperator<HttpClient> factoryDefaults;
|
||||
|
||||
private final UnaryOperator<HttpClient> customizer;
|
||||
|
||||
private final @Nullable ResolvedAddressSelector<? super HttpClientConfig> resolvedAddressSelector;
|
||||
|
||||
public ReactorHttpClientBuilder() {
|
||||
this(HttpClient::create, UnaryOperator.identity(), null);
|
||||
this(HttpClient::create, ReactorHttpClientBuilder::applySpringDefaults, UnaryOperator.identity(), null);
|
||||
}
|
||||
|
||||
private ReactorHttpClientBuilder(Supplier<HttpClient> httpClientFactory, UnaryOperator<HttpClient> customizer,
|
||||
private ReactorHttpClientBuilder(Supplier<HttpClient> factory, UnaryOperator<HttpClient> factoryDefaults,
|
||||
UnaryOperator<HttpClient> customizer,
|
||||
@Nullable ResolvedAddressSelector<? super HttpClientConfig> resolvedAddressSelector) {
|
||||
this.factory = httpClientFactory;
|
||||
this.factory = factory;
|
||||
this.factoryDefaults = factoryDefaults;
|
||||
this.customizer = customizer;
|
||||
this.resolvedAddressSelector = resolvedAddressSelector;
|
||||
}
|
||||
@@ -74,6 +78,7 @@ public final class ReactorHttpClientBuilder {
|
||||
public ReactorHttpClientBuilder withReactorResourceFactory(ReactorResourceFactory reactorResourceFactory) {
|
||||
Assert.notNull(reactorResourceFactory, "'reactorResourceFactory' must not be null");
|
||||
return new ReactorHttpClientBuilder(() -> HttpClient.create(reactorResourceFactory.getConnectionProvider()),
|
||||
this.factoryDefaults,
|
||||
(httpClient) -> this.customizer.apply(httpClient).runOn(reactorResourceFactory.getLoopResources()),
|
||||
this.resolvedAddressSelector);
|
||||
}
|
||||
@@ -86,7 +91,31 @@ public final class ReactorHttpClientBuilder {
|
||||
*/
|
||||
public ReactorHttpClientBuilder withHttpClientFactory(Supplier<HttpClient> factory) {
|
||||
Assert.notNull(factory, "'factory' must not be null");
|
||||
return new ReactorHttpClientBuilder(factory, this.customizer, this.resolvedAddressSelector);
|
||||
return new ReactorHttpClientBuilder(factory, this.factoryDefaults, this.customizer,
|
||||
this.resolvedAddressSelector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ReactorHttpClientBuilder} that does not apply any defaults when
|
||||
* first creating the {@link HttpClient}.
|
||||
* @return a new {@link ReactorHttpClientBuilder} instance
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public ReactorHttpClientBuilder withoutHttpClientDefaults() {
|
||||
return withHttpClientDefaults(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ReactorHttpClientBuilder} that applies the given factory
|
||||
* defaults when first creating the {@link HttpClient}.
|
||||
* @param factoryDefaults the factory to use
|
||||
* @return a new {@link ReactorHttpClientBuilder} instance
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public ReactorHttpClientBuilder withHttpClientDefaults(@Nullable UnaryOperator<HttpClient> factoryDefaults) {
|
||||
return new ReactorHttpClientBuilder(this.factory,
|
||||
(factoryDefaults != null) ? factoryDefaults : UnaryOperator.identity(), this.customizer,
|
||||
this.resolvedAddressSelector);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +126,7 @@ public final class ReactorHttpClientBuilder {
|
||||
*/
|
||||
public ReactorHttpClientBuilder withHttpClientCustomizer(UnaryOperator<HttpClient> customizer) {
|
||||
Assert.notNull(customizer, "'customizer' must not be null");
|
||||
return new ReactorHttpClientBuilder(this.factory,
|
||||
return new ReactorHttpClientBuilder(this.factory, this.factoryDefaults,
|
||||
(httpClient) -> customizer.apply(this.customizer.apply(httpClient)), this.resolvedAddressSelector);
|
||||
}
|
||||
|
||||
@@ -112,7 +141,8 @@ public final class ReactorHttpClientBuilder {
|
||||
public ReactorHttpClientBuilder withResolvedAddressSelector(
|
||||
ResolvedAddressSelector<? super HttpClientConfig> resolvedAddressSelector) {
|
||||
Assert.notNull(resolvedAddressSelector, "'resolvedAddressSelector' must not be null");
|
||||
return new ReactorHttpClientBuilder(this.factory, this.customizer, resolvedAddressSelector);
|
||||
return new ReactorHttpClientBuilder(this.factory, this.factoryDefaults, this.customizer,
|
||||
resolvedAddressSelector);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,7 +152,7 @@ public final class ReactorHttpClientBuilder {
|
||||
*/
|
||||
public HttpClient build(@Nullable HttpClientSettings settings) {
|
||||
settings = (settings != null) ? settings : HttpClientSettings.defaults();
|
||||
HttpClient httpClient = applyDefaults(this.factory.get());
|
||||
HttpClient httpClient = this.factoryDefaults.apply(this.factory.get());
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
httpClient = map.from(settings::connectTimeout).to(httpClient, this::setConnectTimeout);
|
||||
httpClient = map.from(settings::readTimeout).to(httpClient, HttpClient::responseTimeout);
|
||||
@@ -146,11 +176,6 @@ public final class ReactorHttpClientBuilder {
|
||||
: this.resolvedAddressSelector;
|
||||
}
|
||||
|
||||
HttpClient applyDefaults(HttpClient httpClient) {
|
||||
// Aligns with Spring Framework defaults
|
||||
return httpClient.compress(true);
|
||||
}
|
||||
|
||||
private HttpClient setConnectTimeout(HttpClient httpClient, Duration timeout) {
|
||||
return httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) timeout.toMillis());
|
||||
}
|
||||
@@ -177,4 +202,9 @@ public final class ReactorHttpClientBuilder {
|
||||
spec.sslContext(builder.build());
|
||||
}
|
||||
|
||||
static HttpClient applySpringDefaults(HttpClient httpClient) {
|
||||
// Aligns with Spring Framework defaults in ReactorClientHttpRequestFactory
|
||||
return httpClient.compress(true).proxyWithSystemProperties();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+23
@@ -90,6 +90,29 @@ public final class ReactorClientHttpConnectorBuilder
|
||||
this.httpClientBuilder.withHttpClientFactory(factory));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ReactorClientHttpConnectorBuilder} that does not apply any
|
||||
* defaults when first creating the {@link HttpClient}.
|
||||
* @return a new {@link ReactorClientHttpConnectorBuilder} instance
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public ReactorClientHttpConnectorBuilder withoutHttpClientDefaults() {
|
||||
return withHttpClientDefaults(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ReactorClientHttpConnectorBuilder} that applies the given
|
||||
* factory defaults when first creating the {@link HttpClient}.
|
||||
* @param factoryDefaults the factory to use
|
||||
* @return a new {@link ReactorClientHttpConnectorBuilder} instance
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public ReactorClientHttpConnectorBuilder withHttpClientDefaults(
|
||||
@Nullable UnaryOperator<HttpClient> factoryDefaults) {
|
||||
return new ReactorClientHttpConnectorBuilder(getCustomizers(),
|
||||
this.httpClientBuilder.withHttpClientDefaults(factoryDefaults));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ReactorClientHttpConnectorBuilder} that applies additional
|
||||
* customization to the underlying {@link HttpClient}.
|
||||
|
||||
+24
@@ -28,6 +28,7 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ReactorClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ReactorResourceFactory;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
@@ -63,6 +64,29 @@ class ReactorClientHttpRequestFactoryBuilderTests
|
||||
assertThat(called).containsExactly(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void springHttpClientDefaults() {
|
||||
ClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.reactor().build();
|
||||
assertThat(factory).extracting("httpClient.config.acceptGzip").isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withoutHttpClientDefaults() {
|
||||
ClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.reactor()
|
||||
.withoutHttpClientDefaults()
|
||||
.build();
|
||||
assertThat(factory).extracting("httpClient.config.acceptGzip").isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withHttpClientDefaults() {
|
||||
ClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.reactor()
|
||||
.withHttpClientDefaults((httpClient) -> httpClient.baseUrl("test"))
|
||||
.build();
|
||||
assertThat(factory).extracting("httpClient.config.acceptGzip").isEqualTo(false);
|
||||
assertThat(factory).extracting("httpClient.config.baseUrl").isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withReactorResourceFactory() {
|
||||
ReactorResourceFactory resourceFactory = spy(new ReactorResourceFactory());
|
||||
|
||||
+21
@@ -64,6 +64,27 @@ class ReactorClientHttpConnectorBuilderTests
|
||||
assertThat(called).containsExactly(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void springHttpClientDefaults() {
|
||||
ReactorClientHttpConnector connector = ClientHttpConnectorBuilder.reactor().build();
|
||||
assertThat(connector).extracting("httpClient.config.acceptGzip").isEqualTo(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withoutHttpClientDefaults() {
|
||||
ReactorClientHttpConnector connector = ClientHttpConnectorBuilder.reactor().withoutHttpClientDefaults().build();
|
||||
assertThat(connector).extracting("httpClient.config.acceptGzip").isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withHttpClientDefaults() {
|
||||
ReactorClientHttpConnector connector = ClientHttpConnectorBuilder.reactor()
|
||||
.withHttpClientDefaults((httpClient) -> httpClient.baseUrl("test"))
|
||||
.build();
|
||||
assertThat(connector).extracting("httpClient.config.acceptGzip").isEqualTo(false);
|
||||
assertThat(connector).extracting("httpClient.config.baseUrl").isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withReactorResourceFactory() {
|
||||
ReactorResourceFactory resourceFactory = spy(new ReactorResourceFactory());
|
||||
|
||||
Reference in New Issue
Block a user