Skip to content

Latest commit

 

History

History
212 lines (166 loc) · 7.04 KB

web-uris.adoc

File metadata and controls

212 lines (166 loc) · 7.04 KB

UriComponents

UriComponentsBuilder helps to build URI’s from URI templates with variables:

UriComponents uriComponents = UriComponentsBuilder
		.fromUriString("http://example.com/hotels/{hotel}")  // (1)
		.queryParam("q", "{q}")  // (2)
		.encode() // (3)
		.build(); // (4)

URI uri = uriComponents.expand("Westin", "123").toUri();  // (5)
  1. Static factory method with a URI template.

  2. Add and/or replace URI components.

  3. Request to have the URI template and URI variables encoded.

  4. Build a UriComponents.

  5. Expand variables, and obtain the URI.

The above can be consolidated into one chain and shortened with buildAndExpand:

URI uri = UriComponentsBuilder
		.fromUriString("http://example.com/hotels/{hotel}")
		.queryParam("q", "{q}")
		.encode()
		.buildAndExpand("Westin", "123")
		.toUri();

It can be shortened further by going directly to URI (which implies encoding):

URI uri = UriComponentsBuilder
		.fromUriString("http://example.com/hotels/{hotel}")
		.queryParam("q", "{q}")
		.build("Westin", "123");

Or shorter further yet, with a full URI template:

URI uri = UriComponentsBuilder
		.fromUriString("http://example.com/hotels/{hotel}?q={q}")
		.build("Westin", "123");

UriBuilder

Spring MVC and Spring WebFlux

UriComponentsBuilder implements UriBuilder. A UriBuilder in turn can be created with a UriBuilderFactory. Together UriBuilderFactory and UriBuilder provide a pluggable mechanism to build URIs from URI templates, based on shared configuration such as a base url, encoding preferences, and others.

The RestTemplate and the WebClient can be configured with a UriBuilderFactory to customize the preparation of URIs. DefaultUriBuilderFactory is a default implementation of UriBuilderFactory that uses UriComponentsBuilder internally and exposes shared configuration options.

RestTemplate example:

// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;

String baseUrl = "http://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VARIABLES);

RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);

WebClient example:

// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;

String baseUrl = "http://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VARIABLES);

WebClient client = WebClient.builder().uriBuilderFactory(factory).build();

In addition DefaultUriBuilderFactory can also be used directly. It is similar to using UriComponentsBuilder but instead of static factory methods, it is an actual instance that holds configuration and preferences:

String baseUrl = "http://example.com";
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);

URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
		.queryParam("q", "{q}")
		.build("Westin", "123");

URI Encoding

Spring MVC and Spring WebFlux

UriComponentsBuilder exposes encoding options at 2 levels:

  1. {api-spring-framework}/web/util/UriComponentsBuilder.html#encode--[UriComponentsBuilder#encode()] - pre-encodes the URI template first, then strictly encodes URI variables when expanded.

  2. {api-spring-framework}/web/util/UriComponents.html#encode--[UriComponents#encode()] - encodes URI components after URI variables are expanded.

Both options replace non-ASCII and illegal characters with escaped octets, however option 1 also replaces characters with reserved meaning that appear in URI variables.

Tip

Consider ";" which is legal in a path but has reserved meaning. Option 1 replaces ";" with "%3B" in URI variables but not in the URI template. By contrast, option 2 never replaces ";" since it is a legal character in a path.

For most cases option 1 is likely to give the expected result because it treats URI variables as opaque data to be fully encoded, while option 2 is useful only if URI variables intentionally contain reserved characters.

Example usage using option 1:

URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
			.queryParam("q", "{q}")
			.encode()
			.buildAndExpand("New York", "foo+bar")
			.toUri();

	// Result is "/hotel%20list/New%20York?foo%2Bbar"

The above can be shortened by going directly to URI (which implies encoding):

URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
			.queryParam("q", "{q}")
			.build("New York", "foo+bar")

Or shorter further yet, with a full URI template:

URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}?q={q}")
			.build("New York", "foo+bar")

The WebClient and the RestTemplate expand and encode URI templates internally through the UriBuilderFactory strategy. Both can be configured with a custom strategy:

String baseUrl = "http://example.com";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);

// Customize the RestTemplate..
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);

// Customize the WebClient..
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();

The DefaultUriBuilderFactory implementation uses UriComponentsBuilder internally to expand and encode URI templates. As a factory it provides a single place to configure the approach to encoding based on one of the below encoding modes:

  • TEMPLATE_AND_VALUES — uses UriComponentsBuilder#encode(), corresponding to option 1 above, to pre-encode the URI template and strictly encode URI variables when expanded.

  • VALUES_ONLY — does not encode the URI template and instead applies strict encoding to URI variables via UriUtils#encodeUriUriVariables prior to expanding them into the template.

  • URI_COMPONENTS — uses UriComponents#encode(), corresponding to option 2 above, to encode URI component value after URI variables are expanded.

  • NONE — no encoding is applied.

Out of the box the RestTemplate is set to EncodingMode.URI_COMPONENTS for historic reasons and for backwards compatibility. The WebClient relies on the default value in DefaultUriBuilderFactory which was changed from EncodingMode.URI_COMPONENTS in 5.0.x to EncodingMode.TEMPLATE_AND_VALUES in 5.1.