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
spring resttemplate url encoding
提问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 UriTemplate
to 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
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 UriComponentsBuilder
with your spring-web jar.
取决于您使用的 Spring 版本。如果您的版本太旧,例如,版本3.0.6.RELEASE,您将没有UriComponentsBuilder
spring-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
回答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}¶m2={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:
看起来我找到了最好的本地方式(最新)解决方案:
- Do not pass encoded url string as parameter to
RestTemplate.exchange()
- Use URI object instead. Use
UriComponentsBuilder
to construct URI.
- 不要将编码的 url 字符串作为参数传递给
RestTemplate.exchange()
- 改用 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 RestTemplate
client (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 时不要进行编码。