spring resttemplate url编码

时间:2014-01-02 14:52:22

标签: java spring resttemplate

我尝试使用spring resttemplate进行简单的休息调用:

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

endpointUrl变量包含service.host.com/api/service.php

之类的内容

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

因此Spring在创建url之前似乎编码了我的endpointUrl字符串。是否有一种简单的方法可以阻止春天这样做?

此致

6 个答案:

答案 0 :(得分:12)

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

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

RestTemplate

答案 1 :(得分:8)

取决于您使用的是哪个版本的Spring。如果你的版本太旧了,例如版本 3.0.6.RELEASE ,那么你的弹簧网罐就没有UriComponentsBuilder这样的便利。

您需要阻止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);

我使用Spring版本3.0.6.RELEASE进行了测试,它确实有效。

总之,使用restTemplate.getForObject(String url, Object.class)

而不是使用restTemplate.getForObject(java.net.URI uri, Object.class)

请参阅the rest-resttemplate-uri section of the Spring document

答案 2 :(得分:4)

您可以使用带有java.net.URI的重载变体     public T getForObject(URI url,Class responseType)抛出RestClientException

来自Spring's own documentation

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

URI uri = uriComponents.toUri();

答案 3 :(得分:1)

对于任何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()

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

答案 4 :(得分:0)

好像我找到了最佳的本机方式(最新)解决方案:

  1. 请勿将编码的url字符串作为参数传递给dd($items->toArray())
  2. 改为使用URI对象。使用array:3 [▼ 0 => array:3 [▼ "id" => 10 "start_date" => "Jan 1997" "end_date" => "Jan 2000" ] 1 => array:3 [▼ "id" => 9 "start_date" => "Jan 2000" "end_date" => "Jan 2003" ] 2 => array:3 [▼ "id" => 6 "start_date" => "Jan 2007" "end_date" => "" ] ] 来构造URI。

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

array:3 [▼
  0 => array:3 [▼
    "id" => 6
    "start_date" => "Jan 2007"
    "end_date" => ""
  ]
  1 => array:3 [▼
    "id" => 9
    "start_date" => "Jan 2000"
    "end_date" => "Jan 2003"
  ]
  2 => array:3 [▼
    "id" => 10
    "start_date" => "Jan 1997"
    "end_date" => "Jan 2000"
  ]
]

这样,您就不会遇到双重编码问题。

基于Spring $items->sortByDesc('end_date')客户端(包括SOQL查询)调试SalesForce REST客户端时发现解决方案。

答案 5 :(得分:0)

显然,有一种更好的方法可以通过调用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);
}

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