java 避免使用 Spring 的 RestTemplate 对 URL 查询参数进行双重编码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34321361/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 22:45:12  来源:igfitidea点击:

Avoid Double Encoding of URL query param with Spring's RestTemplate

javaspringencoding

提问by cscan

I'm trying to use Spring's RestTemplate::getForObject to make a request for a URL which has a URL query param.

我正在尝试使用 Spring 的 RestTemplate::getForObject 来请求具有 URL 查询参数的 URL。

I've tried:

我试过了:

  • Using a string
  • Creating a URI with URI::new
  • Creating a URI with URI::create
  • Using UriComponentsBuilder to build the URI
  • 使用字符串
  • 使用 URI::new 创建 URI
  • 使用 URI::create 创建 URI
  • 使用 UriComponentsBuilder 构建 URI

No matter which of these I use, encoding the url query param with URLEncoder::encode gets double encoded and using this encoding leaves the url query param unencoded.

无论我使用其中的哪一个,使用 URLEncoder::encode 对 url 查询参数进行编码都会得到双重编码,并且使用此编码会使 url 查询参数未编码。

How can I send this request without double encoding the URL? Here's the method:

如何在不对 URL 进行双重编码的情况下发送此请求?这是方法:

try {
    UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(detectUrl)
            .queryParam("url", URLEncoder.encode(url, "UTF-8"))
            .queryParam("api_key", "KEY")
            .queryParam("api_secret", "SECRET");
    URI uri = builder.build().toUri();
    JSONObject jsonObject = restTemplate.getForObject(uri, JSONObject.class);
    return jsonObject.getJSONArray("face").length() > 0;
} catch (JSONException | UnsupportedEncodingException e) {
    e.printStackTrace();
}

Here's an example:

下面是一个例子:

Without URLEncoder:

没有 URLEncoder:

http://www.example.com/query?url=http://query.param/example&api_key=KEY&api_secret=SECRET

With URLEncoder:

使用 URLEncoder:

http://www.example.com/query?url=http%253A%252F%252Fquery.param%252Fexample&api_key=KEY&api_secret=SECRET

':' should be encoded as %3A and '/' should be encoded as %2F. This does happen - but then the % is encoded as %25.

':' 应编码为 %3A,而 '/' 应编码为 %2F。这确实发生了 - 但随后 % 被编码为 %25。

回答by Sotirios Delimanolis

A UriComponentsBuilderis a builder for UriComponentswhich

AUriComponentsBuilder是一个建造者,UriComponents其中

Represents an immutable collection of URI components, mapping component type to Stringvalues.

表示 URI 组件的不可变集合,将组件类型映射到String值。

The URI specificationdefines what characters are allowed in a URI. This answersummarizes the list to the characters

URI规范定义了什么角色被允许在一个URI。这个答案总结了字符列表

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=

By those rules, your URI

根据这些规则,您的 URI

http://www.example.com/query?url=http://query.param/example&api_key=KEY&api_secret=SECRET

is perfectly valid and requires no additional encoding.

是完全有效的,不需要额外的编码。

The method URLEncoder#encode(String, String)

方法 URLEncoder#encode(String, String)

Translates a string into application/x-www-form-urlencodedformat using a specific encoding scheme.

application/x-www-form-urlencoded使用特定的编码方案将字符串转换为格式。

That is not the same thing. That process is defined here, and URLEncoder(afaik) should be following it pretty closely.

那不是一回事。该过程在此处定义,并且URLEncoder(afaik)应该非常密切地遵循它。

In your original code, using URLEncoder#encodeconverted your input urlinto

在您的原始代码中,使用URLEncoder#encode将您的输入url转换为

http%3A%2F%2Fquery.param%2Fexample

The character %is invalid in a URI so must be encoded. That's what the UriComponentsobject constructed by your UriComponentsBuilderis doing.

该字符%在 URI 中无效,因此必须进行编码。这就是你UriComponents构造的对象UriComponentsBuilder正在做的事情。

This is unnecessary since your URI is completely valid to begin with. Get rid of the use of URLEncoder.

这是不必要的,因为您的 URI 一开始就完全有效。摆脱使用URLEncoder.