UriComponentsBuilder 在两个层面暴露了编码选项。

    这两个选项都用转义的八位数替换非 ASCII 和非法字符。然而,第一个选项也取代了 URI 变量中出现的具有保留意义的字符。

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

    在大多数情况下,第一个选项可能会得到预期的结果,因为它将 URI 变量作为不透明的数据进行完全编码,而第二个选项在 URI 变量有意包含保留字符时很有用。第二个选项在完全不扩展 URI 变量时也很有用,因为这也会对任何偶然看起来像 URI 变量的东西进行编码。

    下面的例子使用的是第一个选项:

    1. URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
    2. .queryParam("q", "{q}")
    3. .encode()
    4. .buildAndExpand("New York", "foo+bar")
    5. .toUri();
    6. // 构建的结果是 "/hotel%20list/New%20York?q=foo%2Bbar"

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

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

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

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

    WebClient 和 RestTemplate 通过 UriBuilderFactory 策略在内部扩展和编码 URI 模板。如下面的例子所示,两者都可以用自定义策略进行配置:

    1. String baseUrl = "https://example.com";
    2. DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
    3. factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
    4. // Customize the RestTemplate..
    5. RestTemplate restTemplate = new RestTemplate();
    6. restTemplate.setUriTemplateHandler(factory);
    7. // Customize the WebClient..
    8. WebClient 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。