URI 链接

本节描述了 Spring Framework 中可用于准备 URI 的各种选项。

UriComponents

Spring MVC 和 Spring WebFlux

UriComponentsBuilder 帮助从带有变量的 URI 模板构建 URI,如以下示例所示

  • Java

  • Kotlin

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

Spring MVC 和 Spring WebFlux

UriComponentsBuilder 实现了 UriBuilder。您可以反过来使用 UriBuilderFactory 创建 UriBuilderUriBuilderFactoryUriBuilder 共同提供了一种可插拔的机制,用于根据共享配置(例如基本 URL、编码偏好和其他详细信息)从 URI 模板构建 URI。

您可以配置 RestTemplateWebClientUriBuilderFactory 以自定义 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 解析

Spring MVC 和 Spring WebFlux

UriComponentsBuilder 支持两种 URI 解析器类型

  1. RFC 解析器——此解析器类型要求 URI 字符串符合 RFC 3986 语法,并将偏离此语法的行为视为非法。

  2. WhatWG 解析器——此解析器基于 WhatWG URL Living standard 中的 URL 解析算法。它对各种意外输入情况提供了宽松的处理。浏览器实现此功能是为了宽松处理用户输入的 URL。有关更多详细信息,请参阅 URL Living Standard 和 URL 解析测试用例

默认情况下,RestClientWebClientRestTemplate 使用 RFC 解析器类型,并期望应用程序提供符合 RFC 语法的 URL 模板。要更改此设置,您可以自定义任何客户端上的 UriBuilderFactory

应用程序和框架可能会进一步依赖 UriComponentsBuilder 来解析用户提供的 URL,以检查并可能验证 URI 组件,例如 scheme、host、port、path 和 query。这些组件可以决定使用 WhatWG 解析器类型,以便更宽松地处理 URL,并在重定向到输入 URL 或将其包含在对浏览器的响应中时,与浏览器解析 URI 的方式保持一致。

URI 编码

Spring MVC 和 Spring WebFlux

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

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

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

在大多数情况下,第一个选项可能会给出预期的结果,因为它将 URI 变量视为不透明数据进行完全编码,而如果 URI 变量确实有意包含保留字符,则第二个选项很有用。当根本不展开 URI 变量时,第二个选项也很有用,因为它也会编码任何偶然看起来像 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 变量展开之后编码 URI 组件值。

  • NONE:不应用任何编码。

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

© . This site is unofficial and not affiliated with VMware.