diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java index c8c0727cad..40bd81342b 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java @@ -274,9 +274,13 @@ final class DefaultWebClientBuilder implements WebClient.Builder { .map(filter -> filter.apply(exchange)) .orElse(exchange) : exchange); + HttpHeaders defaultHeaders = copyDefaultHeaders(); + + MultiValueMap defaultCookies = copyDefaultCookies(); + return new DefaultWebClient(filteredExchange, initUriBuilderFactory(), - this.defaultHeaders != null ? HttpHeaders.readOnlyHttpHeaders(this.defaultHeaders) : null, - this.defaultCookies != null ? CollectionUtils.unmodifiableMultiValueMap(this.defaultCookies) : null, + defaultHeaders, + defaultCookies, this.defaultRequest, new DefaultWebClientBuilder(this)); } @@ -313,4 +317,28 @@ final class DefaultWebClientBuilder implements WebClient.Builder { return factory; } + @Nullable + private HttpHeaders copyDefaultHeaders() { + if (this.defaultHeaders != null) { + HttpHeaders copy = new HttpHeaders(); + this.defaultHeaders.forEach((key, values) -> copy.put(key, new ArrayList<>(values))); + return HttpHeaders.readOnlyHttpHeaders(copy); + } + else { + return null; + } + } + + @Nullable + private MultiValueMap copyDefaultCookies() { + if (this.defaultCookies != null) { + MultiValueMap copy = new LinkedMultiValueMap<>(this.defaultCookies.size()); + this.defaultCookies.forEach((key, values) -> copy.put(key, new ArrayList<>(values))); + return CollectionUtils.unmodifiableMultiValueMap(copy); + } + else { + return null; + } + } + } diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultWebClientTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultWebClientTests.java index db58a16560..47b0956d71 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultWebClientTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/DefaultWebClientTests.java @@ -142,7 +142,8 @@ public class DefaultWebClientTests { @Test public void defaultHeaderAndCookie() { WebClient client = this.builder - .defaultHeader("Accept", "application/json").defaultCookie("id", "123") + .defaultHeader("Accept", "application/json") + .defaultCookie("id", "123") .build(); client.get().uri("/path") @@ -170,6 +171,35 @@ public class DefaultWebClientTests { assertThat(request.cookies().getFirst("id")).isEqualTo("456"); } + @Test + public void defaultHeaderAndCookieCopies() { + WebClient client1 = this.builder + .defaultHeader("Accept", "application/json") + .defaultCookie("id", "123") + .build(); + WebClient client2 = this.builder + .defaultHeader("Accept", "application/xml") + .defaultCookies(cookies -> cookies.set("id", "456")) + .build(); + + client1.get().uri("/path") + .retrieve().bodyToMono(Void.class).block(Duration.ofSeconds(10)); + + ClientRequest request = verifyAndGetRequest(); + assertThat(request.headers().getFirst("Accept")).isEqualTo("application/json"); + assertThat(request.cookies().getFirst("id")).isEqualTo("123"); + + + client2.get().uri("/path") + .retrieve().bodyToMono(Void.class).block(Duration.ofSeconds(10)); + + request = verifyAndGetRequest(); + assertThat(request.headers().getFirst("Accept")).isEqualTo("application/xml"); + assertThat(request.cookies().getFirst("id")).isEqualTo("456"); + + + } + @Test public void defaultRequest() { ThreadLocal context = new NamedThreadLocal<>("foo");