spring-framework/src/docs/asciidoc/web/web-uris.adoc

237 lines
7.6 KiB
Plaintext
Raw Normal View History

[[web-uricomponents]]
= UriComponents
[.small]#Spring MVC and Spring WebFlux#
`UriComponentsBuilder` helps to build URI's from URI templates with variables, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
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 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:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
URI uri = UriComponentsBuilder
.fromUriString("http://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:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
URI uri = UriComponentsBuilder
.fromUriString("http://example.com/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
----
====
You shorter it further still with a full URI template, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
URI uri = UriComponentsBuilder
.fromUriString("http://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123");
----
====
[[web-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`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
// 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);
----
====
The following example configures a `WebClient`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
// 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, 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:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
String baseUrl = "http://example.com";
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);
URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
.queryParam("q", "{q}")
.build("Westin", "123");
----
====
[[web-uri-encoding]]
= URI Encoding
[.small]#Spring MVC and Spring WebFlux#
`UriComponentsBuilder` exposes encoding options at two levels:
2018-07-18 03:58:15 +08:00
* {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.
2018-07-18 03:58:15 +08:00
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.
2018-07-18 03:58:15 +08:00
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.
2018-07-18 03:58:15 +08:00
For most cases, the first option is likely to give the expected result, because it treats URI
2018-07-18 03:58:15 +08:00
variables as opaque data to be fully encoded, while option 2 is useful only if
2018-07-18 04:40:52 +08:00
URI variables intentionally contain reserved characters.
2018-07-18 03:58:15 +08:00
The following example uses the first option:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
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"
2018-07-18 03:58:15 +08:00
----
====
You can shorten the preceding example by going directly to the URI (which implies encoding),
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
URI 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:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}?q={q}")
.build("New York", "foo+bar")
----
====
2018-07-18 03:58:15 +08:00
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:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
String baseUrl = "http://example.com";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
2018-06-12 22:14:35 +08:00
2018-07-18 04:40:52 +08:00
// Customize the RestTemplate..
2018-06-12 22:14:35 +08:00
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
2018-07-18 04:40:52 +08:00
// Customize the WebClient..
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
----
====
2018-07-18 04:40:52 +08:00
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
2018-07-18 04:40:52 +08:00
expanded.
* `VALUES_ONLY`: Does not encode the URI template and, instead, applies strict encoding
to URI variables through `UriUtils#encodeUriUriVariables` prior to expanding them into the
2018-07-18 04:40:52 +08:00
template.
* `URI_COMPONENTS`: Uses `UriComponents#encode()`, corresponding to the second option in the earlier list, to
2018-07-18 03:58:15 +08:00
encode URI component value _after_ URI variables are expanded.
* `NONE`: No encoding is applied.
The `RestTemplate` is set to `EncodingMode.URI_COMPONENTS` for historic
2018-07-18 04:40:52 +08:00
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.