可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I try to do a simple rest call with springs resttemplate:
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
Unfortunately, my call results in a 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?
Regards
回答1:
There is no easy way to do this. URI variables are usually meant for one path element or a query string parameter. You're trying to pass multiple elements.
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
.
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);
回答2:
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.
What you need is to prevent Spring RestTemplate from encoding the URL. What you could do is:
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.
In a word, instead of using restTemplate.getForObject(String url, Object.class)
, use restTemplate.getForObject(java.net.URI uri, Object.class)
See the rest-resttemplate-uri section of the Spring document
回答3:
You can use the overloaded variant that takes a java.net.URI instead 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();
回答4:
Full example with headers, body, for any HttpMethod and ResponseType could look like:
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