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
创建一个UriBuilder
。而UriBuilderFactory
和UriBuilder
一起提供了一个可插拔的机制,根据共享配置(如基本URL、编码偏好和其他细节)从URI模板构建URI。
您可以使用UriBuilderFactory
配置RestTemplate
和WebClient
,以自定义URI的准备过程。 DefaultUriBuilderFactory
是UriBuilderFactory
的默认实现,它在内部使用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
在两个级别上公开编码选项:
-
UriComponentsBuilder#encode():首先对URI模板进行预编码,然后在扩展时严格编码URI变量。
-
UriComponents#encode():在扩展URI变量后对URI组件进行编码。
这两个选项将非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();
// 结果为 "/hotel%20list/New%20York?q=foo%2Bbar"
val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.encode()
.buildAndExpand("New York", "foo+bar")
.toUri()
// 结果为 "/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")
WebClient
和RestTemplate
通过UriBuilderFactory
策略在内部扩展和编码URI模板。两者都可以配置自定义策略,如下例所示:
-
Java
-
Kotlin
String baseUrl = "https://example.com";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
// 自定义RestTemplate..
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
// 自定义WebClient..
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
val baseUrl = "https://example.com"
val factory = DefaultUriBuilderFactory(baseUrl).apply {
encodingMode = EncodingMode.TEMPLATE_AND_VALUES
}
// 自定义RestTemplate..
val restTemplate = RestTemplate().apply {
uriTemplateHandler = factory
}
// 自定义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_COMPONENT
。WebClient
依赖于DefaultUriBuilderFactory
中的默认值,该默认值从5.0.x中的EncodingMode.URI_COMPONENT
更改为5.1中的EncodingMode.TEMPLATE_AND_VALUES
。