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

@@ -167,6 +167,11 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
return new DefaultUriBuilder(uriTemplate);
}
@Override
public UriBuilder builder() {
return new DefaultUriBuilder("");
}
/**
* {@link DefaultUriBuilderFactory} specific implementation of UriBuilder.
@@ -182,9 +187,11 @@ public class DefaultUriBuilderFactory implements UriBuilderFactory {
private UriComponentsBuilder initUriComponentsBuilder(String uriTemplate) {
UriComponentsBuilder result = baseUri.cloneBuilder();
UriComponents child = UriComponentsBuilder.fromUriString(uriTemplate).build();
result.uriComponents(child);
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(uriTemplate);
UriComponents uriComponents = uriComponentsBuilder.build();
UriComponentsBuilder result = (uriComponents.getHost() == null ?
baseUri.cloneBuilder().uriComponents(uriComponents) : uriComponentsBuilder);
if (shouldParsePath()) {
UriComponents uric = result.build();

View File

@@ -30,14 +30,18 @@ package org.springframework.web.util;
public interface UriBuilderFactory extends UriTemplateHandler {
/**
* Return a builder that is initialized with the given URI string which may
* be a URI template and represent full URI or just a path.
* <p>Depending on the factory implementation and configuration, the builder
* may merge the given URI string with a base URI and apply other operations.
* Refer to the specific factory implementation for details.
* @param uriTemplate the URI template to create the builder with
* Return a builder initialized with the given URI string.
* <p>Concrete implementations may apply further initializations such as
* combining with a pre-configured base URI.
* @param uriTemplate the URI template to initialize the builder with
* @return the UriBuilder
*/
UriBuilder uriString(String uriTemplate);
/**
* Return a builder to prepare a new URI.
* @return the UriBuilder
*/
UriBuilder builder();
}

View File

@@ -41,40 +41,48 @@ public class DefaultUriBuilderFactoryTests {
@Test
public void baseUri() throws Exception {
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://foo.com/bar?id=123");
URI uri = factory.uriString("/baz").port(8080).build();
assertEquals("http://foo.com:8080/bar/baz?id=123", uri.toString());
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://foo.com/v1?id=123");
URI uri = factory.uriString("/bar").port(8080).build();
assertEquals("http://foo.com:8080/v1/bar?id=123", uri.toString());
}
@Test
public void baseUriWithFullOverride() throws Exception {
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://foo.com/v1?id=123");
URI uri = factory.uriString("http://example.com/1/2").build();
assertEquals("Use of host should case baseUri to be completely ignored",
"http://example.com/1/2", uri.toString());
}
@Test
public void baseUriWithPathOverride() throws Exception {
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://foo.com/bar");
URI uri = factory.uriString("").replacePath("/baz").build();
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://foo.com/v1");
URI uri = factory.builder().replacePath("/baz").build();
assertEquals("http://foo.com/baz", uri.toString());
}
@Test
public void defaultUriVars() throws Exception {
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/bar");
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/v1");
factory.setDefaultUriVariables(singletonMap("host", "foo.com"));
URI uri = factory.uriString("/{id}").build(singletonMap("id", "123"));
assertEquals("http://foo.com/bar/123", uri.toString());
assertEquals("http://foo.com/v1/123", uri.toString());
}
@Test
public void defaultUriVarsWithOverride() throws Exception {
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/bar");
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/v1");
factory.setDefaultUriVariables(singletonMap("host", "spring.io"));
URI uri = factory.uriString("/baz").build(singletonMap("host", "docs.spring.io"));
assertEquals("http://docs.spring.io/bar/baz", uri.toString());
URI uri = factory.uriString("/bar").build(singletonMap("host", "docs.spring.io"));
assertEquals("http://docs.spring.io/v1/bar", uri.toString());
}
@Test
public void defaultUriVarsWithEmptyVarArg() throws Exception {
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/bar");
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory("http://{host}/v1");
factory.setDefaultUriVariables(singletonMap("host", "foo.com"));
URI uri = factory.uriString("/baz").build();
assertEquals("Expected delegation to build(Map) method", "http://foo.com/bar/baz", uri.toString());
URI uri = factory.uriString("/bar").build();
assertEquals("Expected delegation to build(Map) method", "http://foo.com/v1/bar", uri.toString());
}
@Test