跳到主要内容
版本:7.0.3

URI链接

Hunyuan 7b 中英对照 URI Links

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

UriComponents

Spring MVC 和 Spring WebFlux

UriComponentsBuilder 可帮助根据带有变量的 URI 模板构建 URI,如下例所示:

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
  • 带有URI模板的静态工厂方法。

  • 添加或替换URI组件。

  • \ [#3] 请求对URI模板和变量进行编码。
  • \ [#4] 构建UriComponents对象。
  • \ [#5] 展开变量并获取URI

前面的例子可以整合成一个链式操作,并通过buildAndExpand函数来简化,如下例所示:

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

你可以通过直接使用URI(这涉及到编码)来进一步缩短它,如下例所示:

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

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

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

UriBuilder

Spring MVC和Spring WebFlux

UriComponentsBuilder 实现了 UriBuilder。你可以通过 UriBuilderFactory 来创建一个 UriBuilderUriBuilderFactoryUriBuilder 一起提供了一种可插拔的机制,根据共享配置(如基础 URL、编码偏好以及其他细节)来构建 URI。

你可以使用 UriBuilderFactory 来配置 RestTemplateWebClient,以便自定义 URI 的生成过程。DefaultUriBuilderFactoryUriBuilderFactory 的一个默认实现,它内部使用了 UriComponentsBuilder 并提供了共享的配置选项。

以下示例展示了如何配置一个RestTemplate

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

以下示例配置了一个WebClient

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

此外,你也可以直接使用DefaultUriBuilderFactory。它与使用UriComponentsBuilder类似,但不同的是,DefaultUriBuilderFactory不是一个静态工厂方法,而是一个实际的实例,该实例包含了配置和偏好设置,如下例所示:

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

URI 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生活标准中的URL解析算法。它能对各种意外的输入情况进行较为宽松的处理。浏览器实现这种解析器是为了能够较为宽容地处理用户输入的URL。更多详情,请参阅URL生活标准和URL解析测试用例

默认情况下,RestClientWebClientRestTemplate 使用 RFC 解析器类型,并要求应用程序提供符合 RFC 语法的 URL 模板。要更改这一点,您可以在这些客户端中的任意一个上自定义 UriBuilderFactory

应用程序和框架可能还会根据自身需求依赖UriComponentsBuilder来解析用户提供的URL,以便检查并可能验证URI的各个组成部分,如协议(scheme)、主机(host)、端口(port)、路径(path)和查询参数(query)。这些组件可以选择使用WhatWG解析器类型,以更宽松的方式来处理URL,并与浏览器解析URL的方式保持一致。这在需要重定向到输入URL时,或者当URL作为对浏览器的响应的一部分时尤为有用。

URI编码

Spring MVC 和 Spring WebFlux

UriComponentsBuilder 在两个层面上提供了编码选项:

这两种选项都会将非ASCII字符和非法字符替换为转义八进制字节。然而,第一种选项还会替换出现在URI变量中的具有保留意义的字符。

:::小贴士
可以考虑使用“;”,它在路径中是合法的,但有特定的含义。第一种方法会将“;”在URI变量中替换为“%3B”,但在URI模板中不会进行替换。相比之下,第二种方法永远不会替换“;”,因为“;”是路径中合法的字符。
:::

在大多数情况下,第一种选择很可能会得到预期的结果,因为它将URI变量视为需要完全编码的不透明数据;而第二种选择在URI变量确实包含保留字符时则非常有用。当根本不展开URI变量时,第二种选择也同样适用,因为这样也会对任何看起来像URI变量的内容进行编码。

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

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"

你可以通过直接使用URI来缩短前面的示例(这意味着需要进行编码),如下例所示:

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

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

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

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

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

DefaultUriBuilderFactory的实现内部使用UriComponentsBuilder来扩展和编码URI模板。作为一个工厂,它提供了一个统一的地方来配置编码方式,基于以下编码模式中的一种:

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

  • VALUES_ONLY:不编码 URI 模板,而是在将 URI 变量展开到模板中之前,通过 UriUtils#encodeUriVariables 对这些变量进行严格的编码。

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

  • NONE:不应用任何编码。

出于历史原因和向后兼容性的考虑,RestTemplate被设置为EncodingMode URI COMPONENT。而WebClient则依赖于DefaultUriBuilderFactory的默认值,该默认值在5.0.x版本中是EncodingMode.URI_COMPONENT,但在5.1版本中被修改为EncodingMode.TEMPLATE_ANDVALUES