spring resttemplate url编码

use*_*874 13 java spring resttemplate

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

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

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

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

所以spring似乎在创建url之前编码了我的endpointUrl字符串.是否有一种简单的方法可以防止弹簧这样做?

问候

Sot*_*lis 13

没有简单的方法可以做到这一点.URI变量通常用于一个路径元素或查询字符串参数.你试图传递多个元素.

一种解决方法是使用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);
Run Code Online (Sandbox Code Playgroud)


Dmi*_*nov 11

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

  1. 不要将编码的 url 字符串作为参数传递给 RestTemplate.exchange()
  2. 改用 URI 对象。使用UriComponentsBuilder来构建URI。

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

    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);
*/
Run Code Online (Sandbox Code Playgroud)

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

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


Yuc*_*uci 10

取决于您使用的是哪个版本的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);
Run Code Online (Sandbox Code Playgroud)

我用Spring版本3.0.6.RELEASE测试它,它的工作原理.

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

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


小智 5

您可以使用采用java.net.URI的重载变量,而不是public T getForObject(URI url,Class responseType)抛出RestClientException

Spring自己的文档中

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

URI uri = uriComponents.toUri();
Run Code Online (Sandbox Code Playgroud)