【问题标题】:Encoding query parameters with UriComponentsBuilder使用 UriComponentsBuilder 编码查询参数
【发布时间】:2017-11-10 07:24:46
【问题描述】:

我很难理解UriComponentsBuilder 的行为。我想用它来编码查询参数中的 URL,但它似乎只转义 % 字符,而不是其他必要的字符,例如 &

查询参数中根本没有编码的 URL 示例:

UriComponentsBuilder.fromUri("http://example.com/endpoint")
                    .queryParam("query", "/path?foo=foo&bar=bar")
                    .build();

输出:http://example.com/endpoint?query=/path?foo=foo&bar=bar

这是不正确的,因为未编码的& 导致bar=bar 被解释为/endpoint 的查询参数,而不是/path

但是,如果我使用包含% 字符的输入::

UriComponentsBuilder.fromUri("http://example.com/endpoint")
                    .queryParam("query", "/path?foo=%20bar")
                    .build();

输出:http://example.com/endpoint?query=/path?foo=%2520bar

% 字符被转义。

UriComponentsBuilder 会自动转义 % 字符而不是其他保留字符似乎不一致。

使用UriComponentsBuilder 将 URL 编码为查询参数的正确过程是什么?

【问题讨论】:

  • 但是,据我了解,& 是 URL 中的有效字符。除某些字符外,其他所有内容都必须进行 url 编码。
  • 您找到解决方案了吗?我也遇到了类似的问题

标签: java spring url-encoding query-parameters


【解决方案1】:

在您的示例中,构建 UriComponents 对象未编码或规范化。确保应用编码:

  1. 通过调用encode()方法自行编码(另见normalize()方法):

    UriComponents u = UriComponentsBuilder.fromHttpUrl("http://example.com/endpoint")
      .queryParam("query", "/path?foo=foo&bar=bar")
      .build()
      .encode(); 
    // http://example.com/endpoint?query=/path?foo%3Dfoo%26bar%3Dbar
    
  2. 如果用于构造UriComponents 的参数已经编码,则使用build(true) 方法

    UriComponents u = UriComponentsBuilder.fromHttpUrl("http://example.com/endpoint")
      .queryParam("query", "/path?foo=foo&bar=bar")
      .build(true);
    // IllegalArgumentException: Invalid character '=' for QUERY_PARAM in "/path?foo=foo&bar=bar"
    

HierarchicalUriComponents.encode(String) 方法在底层执行实际编码。在几次内部调用之后,它调用HierarchicalUriComponents.encodeBytes(byte[], HierarchicalUriComponents.Type),其中HierarchicalUriComponents.Type 枚举控制在URL 的哪个部分中允许哪些字符。此检查基于RFC 3986。简而言之,Spring 对 URL 的每一部分都有自己的编码逻辑。

【讨论】:

  • 我不理解这个答案的后半部分。我需要做什么才能修复它?
  • 太棒了。我不知道build()可以带一个参数来避免编码。
  • 你指的normalize()方法是什么?它在UriComponentsBuilder 上不存在。 UriComponents 上有一个,但与编码无关。
【解决方案2】:
  1. 您使用的语法不正确 UriComponentsBuilder.fromUri() 带有 String 参数而不是 一个URI。如果您想将 URL 作为 String 传递,请将其用作:

      UriComponentsBuilder
      .fromUriString("http://example.com/endpoint")
      .queryParam("query", URLEncoder.encode("/path?foo=%20bar","UTF-8"))
      .build();
    
  2. & 是一个有效的 URL 字符,因此它不会被编码,但 % 不是它的原因 被解码为%25

如果您想了解如何将其与RestTemplate 一起使用,请参考:RestTemplate.exchange() does not encode '+'?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    • 2023-02-11
    • 1970-01-01
    • 1970-01-01
    • 2021-01-15
    相关资源
    最近更新 更多