You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
395 lines
12 KiB
395 lines
12 KiB
[[uricomponents]] |
|
= UriComponents |
|
[.small]#Spring MVC and Spring WebFlux# |
|
|
|
`UriComponentsBuilder` helps to build URI's from URI templates with variables, as the following example shows: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
UriComponents uriComponents = UriComponentsBuilder |
|
.fromUriString("https://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 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`. |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
val uriComponents = UriComponentsBuilder |
|
.fromUriString("https://example.com/hotels/{hotel}") // <1> |
|
.queryParam("q", "{q}") // <2> |
|
.encode() // <3> |
|
.build() // <4> |
|
|
|
val uri = uriComponents.expand("Westin", "123").toUri() // <5> |
|
---- |
|
<1> Static factory method with a URI template. |
|
<2> Add 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 preceding example can be consolidated into one chain and shortened with `buildAndExpand`, |
|
as the following example shows: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
URI uri = UriComponentsBuilder |
|
.fromUriString("https://example.com/hotels/{hotel}") |
|
.queryParam("q", "{q}") |
|
.encode() |
|
.buildAndExpand("Westin", "123") |
|
.toUri(); |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
val uri = UriComponentsBuilder |
|
.fromUriString("https://example.com/hotels/{hotel}") |
|
.queryParam("q", "{q}") |
|
.encode() |
|
.buildAndExpand("Westin", "123") |
|
.toUri() |
|
---- |
|
====== |
|
|
|
You can shorten it further by going directly to a URI (which implies encoding), |
|
as the following example shows: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
URI uri = UriComponentsBuilder |
|
.fromUriString("https://example.com/hotels/{hotel}") |
|
.queryParam("q", "{q}") |
|
.build("Westin", "123"); |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
val uri = UriComponentsBuilder |
|
.fromUriString("https://example.com/hotels/{hotel}") |
|
.queryParam("q", "{q}") |
|
.build("Westin", "123") |
|
---- |
|
====== |
|
|
|
You can shorten it further still with a full URI template, as the following example shows: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
URI uri = UriComponentsBuilder |
|
.fromUriString("https://example.com/hotels/{hotel}?q={q}") |
|
.build("Westin", "123"); |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
val uri = UriComponentsBuilder |
|
.fromUriString("https://example.com/hotels/{hotel}?q={q}") |
|
.build("Westin", "123") |
|
---- |
|
====== |
|
|
|
|
|
|
|
[[uribuilder]] |
|
= UriBuilder |
|
[.small]#Spring MVC and Spring WebFlux# |
|
|
|
<<web-uricomponents, `UriComponentsBuilder`>> implements `UriBuilder`. You can create a |
|
`UriBuilder`, in turn, 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 other details. |
|
|
|
You can configure `RestTemplate` and `WebClient` 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. |
|
|
|
The following example shows how to configure a `RestTemplate`: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode; |
|
|
|
String baseUrl = "https://example.org"; |
|
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl); |
|
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES); |
|
|
|
RestTemplate restTemplate = new RestTemplate(); |
|
restTemplate.setUriTemplateHandler(factory); |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode |
|
|
|
val baseUrl = "https://example.org" |
|
val factory = DefaultUriBuilderFactory(baseUrl) |
|
factory.encodingMode = EncodingMode.TEMPLATE_AND_VALUES |
|
|
|
val restTemplate = RestTemplate() |
|
restTemplate.uriTemplateHandler = factory |
|
---- |
|
====== |
|
|
|
The following example configures a `WebClient`: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode; |
|
|
|
String baseUrl = "https://example.org"; |
|
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl); |
|
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES); |
|
|
|
WebClient client = WebClient.builder().uriBuilderFactory(factory).build(); |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode |
|
|
|
val baseUrl = "https://example.org" |
|
val factory = DefaultUriBuilderFactory(baseUrl) |
|
factory.encodingMode = EncodingMode.TEMPLATE_AND_VALUES |
|
|
|
val client = WebClient.builder().uriBuilderFactory(factory).build() |
|
---- |
|
====== |
|
|
|
In addition, you can also use `DefaultUriBuilderFactory` directly. It is similar to using |
|
`UriComponentsBuilder` but, instead of static factory methods, it is an actual instance |
|
that holds configuration and preferences, as the following example shows: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
String baseUrl = "https://example.com"; |
|
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl); |
|
|
|
URI uri = uriBuilderFactory.uriString("/hotels/{hotel}") |
|
.queryParam("q", "{q}") |
|
.build("Westin", "123"); |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
val baseUrl = "https://example.com" |
|
val uriBuilderFactory = DefaultUriBuilderFactory(baseUrl) |
|
|
|
val uri = uriBuilderFactory.uriString("/hotels/{hotel}") |
|
.queryParam("q", "{q}") |
|
.build("Westin", "123") |
|
---- |
|
====== |
|
|
|
|
|
[[uri-encoding]] |
|
= URI Encoding |
|
[.small]#Spring MVC and Spring WebFlux# |
|
|
|
`UriComponentsBuilder` exposes encoding options at two levels: |
|
|
|
* {api-spring-framework}/web/util/UriComponentsBuilder.html#encode--[UriComponentsBuilder#encode()]: |
|
Pre-encodes the URI template first and then strictly encodes URI variables when expanded. |
|
* {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, the first option |
|
also replaces characters with reserved meaning that appear in URI variables. |
|
|
|
TIP: Consider ";", which is legal in a path but has reserved meaning. The first option replaces |
|
";" with "%3B" in URI variables but not in the URI template. By contrast, the second option never |
|
replaces ";", since it is a legal character in a path. |
|
|
|
For most cases, the first option is likely to give the expected result, because it treats URI |
|
variables as opaque data to be fully encoded, while the second option is useful if URI |
|
variables do intentionally contain reserved characters. The second option is also useful |
|
when not expanding URI variables at all since that will also encode anything that |
|
incidentally looks like a URI variable. |
|
|
|
The following example uses the first option: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}") |
|
.queryParam("q", "{q}") |
|
.encode() |
|
.buildAndExpand("New York", "foo+bar") |
|
.toUri(); |
|
|
|
// Result is "/hotel%20list/New%20York?q=foo%2Bbar" |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
val uri = UriComponentsBuilder.fromPath("/hotel list/{city}") |
|
.queryParam("q", "{q}") |
|
.encode() |
|
.buildAndExpand("New York", "foo+bar") |
|
.toUri() |
|
|
|
// Result is "/hotel%20list/New%20York?q=foo%2Bbar" |
|
---- |
|
====== |
|
|
|
You can shorten the preceding example by going directly to the URI (which implies encoding), |
|
as the following example shows: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}") |
|
.queryParam("q", "{q}") |
|
.build("New York", "foo+bar"); |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
val uri = UriComponentsBuilder.fromPath("/hotel list/{city}") |
|
.queryParam("q", "{q}") |
|
.build("New York", "foo+bar") |
|
---- |
|
====== |
|
|
|
You can shorten it further still with a full URI template, as the following example shows: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
URI uri = UriComponentsBuilder.fromUriString("/hotel list/{city}?q={q}") |
|
.build("New York", "foo+bar"); |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
val uri = UriComponentsBuilder.fromUriString("/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, |
|
as the following example shows: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"] |
|
---- |
|
String baseUrl = "https://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(); |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] |
|
---- |
|
val baseUrl = "https://example.com" |
|
val factory = DefaultUriBuilderFactory(baseUrl).apply { |
|
encodingMode = EncodingMode.TEMPLATE_AND_VALUES |
|
} |
|
|
|
// Customize the RestTemplate.. |
|
val restTemplate = RestTemplate().apply { |
|
uriTemplateHandler = factory |
|
} |
|
|
|
// Customize the WebClient.. |
|
val 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 |
|
the first option in the earlier list, 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 through `UriUtils#encodeUriVariables` prior to expanding them into the |
|
template. |
|
* `URI_COMPONENT`: Uses `UriComponents#encode()`, corresponding to the second option in the earlier list, to |
|
encode URI component value _after_ URI variables are expanded. |
|
* `NONE`: No encoding is applied. |
|
|
|
The `RestTemplate` is set to `EncodingMode.URI_COMPONENT` for historic |
|
reasons and for backwards compatibility. The `WebClient` relies on the default value |
|
in `DefaultUriBuilderFactory`, which was changed from `EncodingMode.URI_COMPONENT` in |
|
5.0.x to `EncodingMode.TEMPLATE_AND_VALUES` in 5.1.
|
|
|