Better support for overriding base URI in WebClient

The base URI is ignored for requests that include a host.

WebClient exposes UriBuilder (rather than UriBuilderFactory) for
per-request URI building based on the base URI. That provides
full control to add or replace components of the base URI.
This commit is contained in:
Rossen Stoyanchev
2017-02-02 17:09:53 -05:00
parent 82a34f4b24
commit 1466c82f53
6 changed files with 93 additions and 36 deletions

View File

@@ -38,6 +38,7 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriBuilderFactory;
@@ -150,8 +151,8 @@ class DefaultWebClient implements WebClient {
}
@Override
public HeaderSpec uri(Function<UriBuilderFactory, URI> uriFunction) {
return uri(uriFunction.apply(getUriBuilderFactory()));
public HeaderSpec uri(Function<UriBuilder, URI> uriFunction) {
return uri(uriFunction.apply(getUriBuilderFactory().builder()));
}
@Override

View File

@@ -31,6 +31,7 @@ import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ClientHttpRequest;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriBuilderFactory;
/**
@@ -113,6 +114,7 @@ public interface WebClient {
/**
* Create a new {@code WebClient} with no default, shared preferences across
* requests such as base URI, default headers, and others.
* @see #create(String)
*/
static WebClient create() {
return new DefaultWebClientBuilder().build();
@@ -123,33 +125,48 @@ public interface WebClient {
* example to avoid repeating the same host, port, base path, or even
* query parameters with every request.
*
* <p>Given the following initialization:
* <p>For example given this initialization:
* <pre class="code">
* WebClient client = WebClient.create("http://abc.com/v1");
* </pre>
*
* <p>A base URI is applied when using a URI template:
* <p>The base URI is applied to exchanges with a URI template:
* <pre class="code">
*
* // GET http://abc.com/v1/accounts/43
*
* Mono&#060;Account&#062; result = client.get()
* .uri("/accounts/{id}", 43)
* .exchange()
* .then(response -> response.bodyToMono(String.class));
* .then(response -> response.bodyToMono(Account.class));
* </pre>
*
* <p>It is also applied when using a {@link UriBuilderFactory}:
* <p>The base URI is also applied to exchanges with a {@code UriBuilder}:
* <pre class="code">
* // GET http://abc.com/v1/accounts?q=12
*
* Mono&#060;Account&#062; result = client.get()
* .uri(factory -> factory.uriString("/accounts").queryParam("q", "12").build())
* Flux&#060;Account&#062; result = client.get()
* .uri(builder -> builder.path("/accounts").queryParam("q", "12").build())
* .exchange()
* .then(response -> response.bodyToMono(String.class));
* .then(response -> response.bodyToFlux(Account.class));
* </pre>
*
* <p>The base URI can be overridden with an absolute URI:
* <pre class="code">
* // GET http://xyz.com/path
* Mono&#060;Account&#062; result = client.get()
* .uri("http://xyz.com/path")
* .exchange()
* .then(response -> response.bodyToMono(Account.class));
* </pre>
*
* <p>The base URI can be partially overridden with a {@code UriBuilder}:
* <pre class="code">
* // GET http://abc.com/v2/accounts?q=12
* Flux&#060;Account&#062; result = client.get()
* .uri(builder -> builder.replacePath("/v2/accounts").queryParam("q", "12").build())
* .exchange()
* .then(response -> response.bodyToFlux(Account.class));
* </pre>
*
*
* @param baseUrl the base URI for all requests
*/
static WebClient create(String baseUrl) {
@@ -284,7 +301,7 @@ public interface WebClient {
* Build the URI for the request using the {@link UriBuilderFactory}
* configured for this client.
*/
HeaderSpec uri(Function<UriBuilderFactory, URI> uriFunction);
HeaderSpec uri(Function<UriBuilder, URI> uriFunction);
}

View File

@@ -64,6 +64,26 @@ public class DefaultWebClientTests {
assertEquals(Collections.emptyMap(), request.cookies());
}
@Test
public void uriBuilder() throws Exception {
WebClient client = builder().build();
client.get().uri(builder -> builder.path("/path").queryParam("q", "12").build()).exchange();
ClientRequest<?> request = verifyExchange();
assertEquals("/base/path?q=12", request.url().toString());
verifyNoMoreInteractions(this.exchangeFunction);
}
@Test
public void uriBuilderWithPathOverride() throws Exception {
WebClient client = builder().build();
client.get().uri(builder -> builder.replacePath("/path").build()).exchange();
ClientRequest<?> request = verifyExchange();
assertEquals("/path", request.url().toString());
verifyNoMoreInteractions(this.exchangeFunction);
}
@Test
public void requestHeaderAndCookie() throws Exception {
WebClient client = builder().build();