【问题标题】:Encoding a URL Query Parameter so it can have a '+'对 URL 查询参数进行编码,使其可以具有“+”
【发布时间】:2021-07-23 06:03:04
【问题描述】:

显然,在从 Spring Boot 1 迁移到 Spring Boot 2(Spring 5)的过程中,RestTemplates 的 URL 参数的编码行为发生了变化。在传递的其余模板上获取通用查询参数似乎异常困难,以便正确转义具有特殊含义的字符,例如“+”。看来,由于“+”是一个有效字符,它不会被转义,即使它的 含义 被改变了(参见here)。这似乎很奇怪,违反直觉,并且违反了所有其他平台上的所有其他约定。更重要的是,我不知道如何轻松绕过它。如果我先对字符串进行编码,它会被双重编码,因为“%”会被重新编码。无论如何,这似乎应该是框架所做的非常简单的事情,但我没有弄清楚。

这是我在 Spring Boot 1 中工作的代码:

  String url = "https://base/url/here";
  UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
  for (Map.Entry<String, String> entry : query.entrySet()) {
    builder.queryParam(entry.getKey(), entry.getValue());
  }
  HttpEntity<TheResponse> resp = myRestTemplate.exchange(builder.toUriString(), ...);

但是,现在它不会对“+”字符进行编码,因此另一端将其解释为空格。在 Java Spring Boot 2 中构建此 URL 的正确方法是什么?

注意 - 我也试过这个,但它实际上对所有内容都进行了双重编码:

try {
  for (Map.Entry<String, String> entry : query.entrySet()) {
    builder.queryParam(entry.getKey(), URLEncoder.encode(entry.getValue(),"UTF-8" ));
  }
} catch(Exception e) {
  System.out.println("Encoding error");
}

在第一个中,如果我输入 "q" => "abc+1@efx.com",那么,恰好在 URL 中,我得到 "abc+1@efx.com"(即,未编码完全)。但是,在第二个中,如果我输入“abc+1@efx.com”,则会得到“abc%252B1%2540efx.com”,它是双编码的。

我可以手写一个编码方法,但这似乎 (a) 有点矫枉过正,并且 (b) 自己进行编码是安全问题和奇怪错误趋于蔓延的地方。但似乎对我来说很疯狂,您不能只在 Spring Boot 2 中添加查询参数。这似乎是一项基本任务。我错过了什么?

【问题讨论】:

    标签: java spring spring-boot resttemplate spring-resttemplate


    【解决方案1】:

    找到了我认为不错的解决方案。事实证明,问题的很大一部分实际上是“交换”函数,它接受一个字符串作为 URL,但由于我无法理解的原因重新编码该 URL。但是,可以改为向交换函数发送 java.net.URI。在这种情况下,它不会尝试插入任何内容,因为它已经是一个 URI。然后我使用 java.net.URLEncoder.encode() 对片段进行编码。我仍然不知道为什么这在 Spring 中不是标准的,但这应该可以工作。

        private String mapToQueryString(Map<String, String> query) {
            List<String> entries = new LinkedList<String>();
            for (Map.Entry<String, String> entry : query.entrySet()) {
                try {
                    entries.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8"));
                } catch(Exception e) {
                    log.error("Unable to encode string for URL: " + entry.getKey() + " / " + entry.getValue(), e);
                }
            }
            return String.join("&", entries);
        }
    
        /* Later in the code */
        String endpoint = "https://baseurl.example.com/blah";
        String finalUrl = query.isEmpty() ? endpoint : endpoint + "?" + mapToQueryString(query);
        URI uri;
        try {
            uri = new URI(finalUrl);
        } catch(URISyntaxException e) {
            log.error("Bad URL // " + finalUrl, e);
                return null;
            }
        }
        /* ... */
        HttpEntity<TheResponse> resp = myRestTemplate.exchange(uri, ...)
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-20
      • 2011-09-06
      • 1970-01-01
      • 2018-01-22
      • 1970-01-01
      • 2014-11-16
      • 1970-01-01
      • 2015-09-13
      相关资源
      最近更新 更多