URI Links

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

UriComponents

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

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

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

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

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

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

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 带有 URI 模板的静态工厂方法。
2 添加或替换 URI 组件。
3 请求对 URI 模板和 URI 变量进行编码。
4 Build a UriComponents.
5 展开变量并获取 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 带有 URI 模板的静态工厂方法。
7 添加或替换 URI 组件。
8 请求对 URI 模板和 URI 变量进行编码。
9 Build a UriComponents.
10 展开变量并获取 URI

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

  • 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(这意味着编码),如下例所示:

  • 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 模板进一步缩短它,如下例所示:

  • 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

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

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

以下示例显示如何配置 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

  • 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,但不是静态工厂方法,而是一个实际的实例,包含配置和首选项,如下例所示:

  • 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

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

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

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

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

以下示例使用第一个选项:

  • 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(这意味着编码)来缩短前面的示例,如下例所示:

  • 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 模板进一步缩短它,如下例所示:

  • 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 模板。两个都可以使用自定义策略进行配置,如下例所示:

  • 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 模板。作为工厂,它提供了一个单一的位置来配置编码方法,基于以下编码模式之一:

  • TEMPLATE_AND_VALUES: 使用 UriComponentsBuilder#encode(),对应于前一个列表中的第一个选项,预编码 URI 模板,并在展开时严格编码 URI 变量。

  • VALUES_ONLY: 不编码 URI 模板,而是通过 `UriUtils#encodeUriVariables`在将它们展开到模板前,对 URI 变量应用严格编码。

  • URI_COMPONENT: 使用 UriComponents#encode(),对应于前一个列表中的第二个选项,对 URI 组件值进行编码 after URI 变量被展开。

  • NONE: 不应用任何编码。

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