URI Links

本部分介绍 Spring Framework 中为准备 URI 而提供的各种选项。

This section describes various options available in the Spring Framework to prepare URIs.

UriComponents

  1. 通过静态工厂方法从 URI 模板创建 URI 组件。

  2. 添加或替换 URI 组件,例如查询参数或路径变量。

  3. 对 URI 模板和 URI 变量进行编码,以确保跨网络安全传输。

  4. 构建 UriComponents 对象,其中包含 URI 模板和变量。

  5. 展开变量并获取 URI,生成最终的请求 URI。 Spring MVC and Spring WebFlux

UriComponentsBuilder 有助于通过具有变量的 URI 模板来构建 URI,如下例所示:

UriComponentsBuilder helps to build URI’s from URI templates with variables, as the following example shows:

Java
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
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)
6 Static factory method with a URI template.
7 Add or replace URI components.
8 Request to have the URI template and URI variables encoded.
9 Build a UriComponents.
10 Expand variables and obtain the URI.

前面的示例可以合并到一个链中并使用 buildAndExpand 缩短,如下例所示:

The preceding example can be consolidated into one chain and shortened with buildAndExpand, as the following example shows:

  • Java

  • Kotlin

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

您可以更进一步缩短它,直接转到 URI(这意味着编码),如下例所示:

You can shorten it further by going directly to a URI (which implies encoding), as the following example shows:

  • Java

  • Kotlin

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

您还可以使用完整的 URI 模板进一步缩短它,如下例所示:

You can shorten it further still with a full URI template, as the following example shows:

  • Java

  • Kotlin

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

UriBuilder

[role="small"][.small]Spring MVC 和 Spring WebFlux

[role="small"][.small]Spring MVC and Spring WebFlux

<<`UriComponentsBuilder`,web-uricomponents>> 实现 UriBuilder。您可以创建一个 UriBuilder,反过来,可以使用 UriBuilderFactory 创建一个 UriBuilderUriBuilderFactoryUriBuilder 一起提供了一种可插入机制,用于基于共享配置(例如基本 URL、编码首选项和其他详细信息)从 URI 模板构建 URI。

<<`UriComponentsBuilder`,web-uricomponents>> 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.

您可以使用 UriBuilderFactory 配置 RestTemplateWebClient 以自定义 URI 的准备。DefaultUriBuilderFactoryUriBuilderFactory 的默认实现,它在内部使用 UriComponentsBuilder 并公开共享配置选项。

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.

以下示例显示如何配置 RestTemplate

The following example shows how to configure a RestTemplate:

  • Java

  • Kotlin

// 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);
// 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

以下示例配置 WebClient

The following example configures a WebClient:

  • Java

  • Kotlin

// 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();
// 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()

此外,您还可以直接使用 DefaultUriBuilderFactory。它类似于使用 UriComponentsBuilder,但不是静态工厂方法,而是一个实际的实例,包含配置和首选项,如下例所示:

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:

  • Java

  • Kotlin

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

URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
		.queryParam("q", "{q}")
		.build("Westin", "123");
val baseUrl = "https://example.com"
val uriBuilderFactory = DefaultUriBuilderFactory(baseUrl)

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

URI Encoding

[role="small"][.small]Spring MVC 和 Spring WebFlux

[role="small"][.small]Spring MVC and Spring WebFlux

UriComponentsBuilder 在两个级别上公开编码选项:

UriComponentsBuilder exposes encoding options at two levels:

这两个选项都将非 ASCII 和非法字符替换为转义的八位字节序列。但是,第一个选项还将出现在 URI 变量中的保留含义字符替换为转义字符。

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.

考虑“;”这个分号在路径中是合法的,但在 URI 模板中不合法,保留着含义。第一个选项用 URI 变量中的“;”替换为“%3B”,但不会将 URI 模板中的“;”替换为“%3B”。相比之下,第二个选项永远不会替换“;”,因为它是路径中的一个合法字符。

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.

对于大多数情况,第一个选项可能会提供预期的结果,因为它将 URI 变量作为要完全编码的不透明数据进行处理,而第二个选项在 URI 变量有意包含保留字符时很有用。第二个选项在根本未扩展 URI 变量时也很有用,因为这也会对偶发 trông giống như một biến URI 的任何内容进行编码。

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:

  • Java

  • Kotlin

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"
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"

您可以通过直接转到 URI(这意味着编码)来缩短前面的示例,如下例所示:

You can shorten the preceding example by going directly to the URI (which implies encoding), as the following example shows:

  • Java

  • Kotlin

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

您还可以使用完整的 URI 模板进一步缩短它,如下例所示:

You can shorten it further still with a full URI template, as the following example shows:

  • Java

  • Kotlin

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

WebClientRestTemplate 通过 UriBuilderFactory 策略在内部展开和编码 URI 模板。两个都可以使用自定义策略进行配置,如下例所示:

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:

  • Java

  • Kotlin

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();
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()

DefaultUriBuilderFactory 实现内部使用 UriComponentsBuilder 来展开和编码 URI 模板。作为工厂,它提供了一个单一的位置来配置编码方法,基于以下编码模式之一:

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.

RestTemplate 设置为 EncodingMode.URI_COMPONENT 是出于历史原因和向后兼容性的考虑。WebClient 依赖于 DefaultUriBuilderFactory 中的默认值,该值已从 5.0.x 中 的 EncodingMode.URI_COMPONENT 更改为 5.1 中的 EncodingMode.TEMPLATE_AND_VALUES

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.