Java spring resttemplate url 编码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20885521/
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-08-13 05:00:51  来源:igfitidea点击:

spring resttemplate url encoding

javaspringresttemplate

提问by user1145874

I try to do a simple rest call with springs resttemplate:

我尝试用 springs resttemplate 做一个简单的 rest 调用:

private void doLogout(String endpointUrl, String sessionId) {
    template.getForObject("http://{enpointUrl}?method=logout&session={sessionId}", Object.class,
            endpointUrl, sessionId);
}

Where the endpointUrl variable contains something like service.host.com/api/service.php

其中 endpointUrl 变量包含类似 service.host.com/api/service.php 的内容

Unfortunately, my call results in a org.springframework.web.client.ResourceAccessException: I/O error: service.host.com%2Fapi%2Fservice.php

不幸的是,我的调用导致 org.springframework.web.client.ResourceAccessException: I/O error: service.host.com%2Fapi%2Fservice.php

So spring seems to encode my endpointUrl string before during the creation of the url. Is there a simple way to prevent spring from doing this?

所以 spring 似乎在创建 url 之前对我的 endpointUrl 字符串进行了编码。有没有一种简单的方法可以防止 spring 这样做?

Regards

问候

采纳答案by Sotirios Delimanolis

There is no easy way to do this. URI template variables are usually meant for path elements or a query string parameters. You're trying to pass a host. Ideally, you'd find a better solution for constructing the URI. I suggest Yuci's solution.

没有简单的方法可以做到这一点。URI 模板变量通常用于路径元素或查询字符串参数。你试图通过一个主机。理想情况下,您会找到构建 URI 的更好解决方案。我建议Yuci 的解决方案

If you still want to work with Spring utilities and template expansion, one workaround is to use UriTemplateto produce the URL with the URI variables as you have them, then URL-decode it and pass that to your RestTemplate.

如果您仍然想使用 Spring 实用程序和模板扩展,一种解决方法是使用UriTemplate您拥有的 URI 变量生成 URL,然后对其进行 URL 解码并将其传递给您的RestTemplate.

String url = "http://{enpointUrl}?method=logout&session={sessionId}";
URI expanded = new UriTemplate(url).expand(endpointUrl, sessionId); // this is what RestTemplate uses 
url = URLDecoder.decode(expanded.toString(), "UTF-8"); // java.net class
template.getForObject(url, Object.class);

回答by Not a code monkey

You can use the overloaded variant that takes a java.net.URI instead public T getForObject(URI url, Class responseType) throws RestClientException

您可以使用采用 java.net.URI 的重载变体代替 public T getForObject(URI url, Class responseType) throws RestClientException

From Spring's own documentation

来自Spring 自己的文档

UriComponents uriComponents =
    UriComponentsBuilder.fromUriString("http://example.com/hotels/{hotel}/bookings/{booking}").build()
        .expand("42", "21")
        .encode();

URI uri = uriComponents.toUri();

回答by Yuci

Depends on which version of Spring you're using. If your version is too old, for example, version 3.0.6.RELEASE, you'll not have such facility as UriComponentsBuilderwith your spring-web jar.

取决于您使用的 Spring 版本。如果您的版本太旧,例如,版本3.0.6.RELEASE,您将没有UriComponentsBuilderspring-web jar那样的便利

What you need is to prevent Spring RestTemplate from encoding the URL. What you could do is:

您需要的是防止 Spring RestTemplate 对 URL 进行编码。你可以做的是:

import java.net.URI;

StringBuilder builder = new StringBuilder("http://");
builder.append(endpointUrl);
builder.append("?method=logout&session=");
builder.append(sessionId);

URI uri = URI.create(builder.toString());
restTemplate.getForObject(uri, Object.class);

I tested it with Spring version 3.0.6.RELEASE, and it works.

我使用 Spring 版本 3.0.6.RELEASE 对其进行了测试,并且可以正常工作。

In a word, instead of using restTemplate.getForObject(String url, Object.class), use restTemplate.getForObject(java.net.URI uri, Object.class)

总之,不要使用restTemplate.getForObject(String url, Object.class),而是使用restTemplate.getForObject(java.net.URI uri, Object.class)

See the rest-resttemplate-uri section of the Spring document

请参阅Spring 文档的 rest-resttemplate-uri 部分

回答by Geniy

Full example with headers, body, for any HttpMethod and ResponseType could look like:

任何 HttpMethod 和 ResponseType 的带有标头、正文的完整示例可能如下所示:

String url = "http://google.com/{path}?param1={param1Value}&param2={param2Value}";
Object body = null;
HttpEntity request = new HttpEntity(body, new HttpHeaders());

Map<String, String> uriVariables = new HashMap<>();
uriVariables.put("path", "search");
uriVariables.put("param1Value", "value1");
uriVariables.put("param2Value", "value2");

ResponseEntity<Void> responseEntity = restTemplate.exchange(url, HttpMethod.POST, request, Void.class, uriVariables)
//responseEntity.getBody()

Actually, it will use the same UriTemplate and expand method

实际上,它将使用相同的 UriTemplate 和 expand 方法

回答by Dmitry Trifonov

Looks like I found best native way (up-to-date) solution:

看起来我找到了最好的本地方式(最新)解决方案:

  1. Do not pass encoded url string as parameter to RestTemplate.exchange()
  2. Use URI object instead. Use UriComponentsBuilderto construct URI.
  1. 不要将编码的 url 字符串作为参数传递给 RestTemplate.exchange()
  2. 改用 URI 对象。使用UriComponentsBuilder来构建URI。

See (simplified) example below:

请参阅下面的(简化)示例:

    String instanceUrl = "https://abc.my.salesforce.com"
    HttpEntity<String> entity = new HttpEntity<>(headers);
    UriComponents uriComponents =
            UriComponentsBuilder.fromHttpUrl(instanceUrl)
                    .path("/services/data/v45.0/query/")
                    .queryParam("q", String.format(sqlSelect, id))
                    .build();

    ResponseEntity<OpportunityLineItem> responseEntity =
            restTemplate.exchange(
                    uriComponents.toUri(), HttpMethod.GET,
                    entity, OpportunityLineItem.class);

// Wrong! URI string will be double encoded
/*
ResponseEntity<OpportunityLineItem> responseEntity =
            restTemplate.exchange(
                    uriComponents.toUriString(), HttpMethod.GET,
                    entity, OpportunityLineItem.class);
*/

This way you will not get issue with double encoding.

这样你就不会遇到双重编码的问题。

Solution was found while debugging SalesForce REST client, based on Spring RestTemplateclient (including SOQL queries).

解决方案是在调试 SalesForce REST 客户端时找到的,基于 SpringRestTemplate客户端(包括 SOQL 查询)。

回答by mtk.94

Apparently there is a better way to do this by calling build(true) of class UriComponentsBuilder:

显然有一种更好的方法可以通过调用 UriComponentsBuilder 类的 build(true) 来做到这一点:

private void doLogout(String endpointUrl, String sessionId) {
    String url = "http://" + endpointUrl +"?method=logout&session=" + + URLEncoder.encode(sessionId, "UTF-8");
    URI uri = UriComponentsBuilder.fromUriString(url.toString()).build(true).toUri();
    template.getForObject(uri, Object.class,
            endpointUrl, sessionId);
}

This method tells URIComponentsBuilder not to encode while creating URI.

此方法告诉 URIComponentsBuilder 在创建 URI 时不要进行编码。