在Spring中使用RestTemplate。例外 - 没有足够的变量可用于扩展

时间:2014-02-17 01:22:40

标签: spring resttemplate

我正在尝试访问API的内容,我需要使用RestTemplate发送URL。

String url1 = "http://api.example.com/Search?key=52ddafbe3ee659bad97fcce7c53592916a6bfd73&term=&limit=100&sort={\"price\":\"desc\"}";

OutputPage page = restTemplate.getForObject(url1, OutputPage .class);

但是,我收到以下错误。

Exception in thread "main" java.lang.IllegalArgumentException: Not enough variable values available to expand '"price"'
at org.springframework.web.util.UriComponents$VarArgsTemplateVariables.getValue(UriComponents.java:284)
at org.springframework.web.util.UriComponents.expandUriComponent(UriComponents.java:220)
at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:317)
at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:46)
at org.springframework.web.util.UriComponents.expand(UriComponents.java:162)
at org.springframework.web.util.UriTemplate.expand(UriTemplate.java:119)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:501)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:239)
at hello.Application.main(Application.java:26)

如果我删除排序条件,它就能正常工作。 我需要使用排序条件解析JSON。 任何帮助将不胜感激。

由于

6 个答案:

答案 0 :(得分:47)

根本原因是RestTemplate将给定URL中的花括号{...}视为URI变量的占位符,并尝试根据其名称替换它们。例如

{pageSize}

会尝试获取名为pageSize的URI变量。这些URI变量是使用其他一些重载的getForObject方法指定的。您没有提供任何内容,但您的URL需要一个,因此该方法会抛出异常。

一种解决方案是创建一个包含值

String对象
String sort = "{\"price\":\"desc\"}";

并在您的网址

中提供真实的URI变量
String url1 = "http://api.example.com/Search?key=52ddafbe3ee659bad97fcce7c53592916a6bfd73&term=&limit=100&sort={sort}";

您可以这样打电话给getForObject()

OutputPage page = restTemplate.getForObject(url1, OutputPage.class, sort);

我强烈建议您不要在GET请求的请求参数中发送任何JSON,而是将其发送到POST请求的正文中。

答案 1 :(得分:5)

您可以对参数值进行URL编码:

String url1 = "http://api.example.com/Search?key=52ddafbe3ee659bad97fcce7c53592916a6bfd73&term=&limit=100&sort=";

org.apache.commons.codec.net.URLCodec codec = new org.apache.commons.codec.net.URLCodec();
url1 = url1 + codec.encode("{\"price\":\"desc\"}");
OutputPage page = restTemplate.getForObject(url1, OutputPage.class);

答案 2 :(得分:3)

如果在场景中很难实现sotirios-delimanolis建议的解决方案,并且如果保证包含大括号和其他字符的URI字符串是正确的,则传递编码后的URI字符串可能会更简单到RestTemplate服务器上的ReST方法。

可以使用UriComponentsBuilder.build()构建URI字符串,使用UriComponents.encode()进行编码,并使用RestTemplate.exchange()发送URI字符串,如下所示:

public ResponseEntity<Object> requestRestServer()
{
    HttpEntity<?> entity = new HttpEntity<>(requestHeaders);
    UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(rawValidUrl)
            .queryParams(
                    (LinkedMultiValueMap<String, String>) allRequestParams);
    UriComponents uriComponents = builder.build().encode();
    ResponseEntity<Object> responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.GET,
            entity, String.class);
    return responseEntity;
}

在上面的代码片段中,为清楚起见,对URI的构建,编码和提取进行了分离。

答案 3 :(得分:1)

您可以在使用RestTemplate之前对URL进行编码

URLEncoder.encode(data, StandardCharsets.UTF_8.toString());

答案 4 :(得分:1)

您可以在restTemplate中设置特定的UriTemplateHandler。该处理程序只会忽略uriVariables:

UriTemplateHandler skipVariablePlaceHolderUriTemplateHandler = new UriTemplateHandler() {
    @Override
    public URI expand(String uriTemplate, Object... uriVariables) {
        return retrieveURI(uriTemplate);
    }

    @Override
    public URI expand(String uriTemplate, Map<String, ?> uriVariables) {
        return retrieveURI(uriTemplate);
    }

    private URI retrieveURI(String uriTemplate) {
        return UriComponentsBuilder.fromUriString(uriTemplate).build().toUri();
    }
};

restTemplate.setUriTemplateHandler(skipVariablePlaceHolderUriTemplateHandler);

答案 5 :(得分:0)

您可以简单地将一个变量附加到Url并在 restTemplate.postForObject 方法中传递该变量的值。

String url1 = "http://api.example.com/Search? 
key=52ddafbe3ee659bad97fcce7c53592916a6bfd73&term=&limit=100&sort={data}";
String data="{\"price\":\"desc\"}";
OutputPage page = restTemplate.getForObject(url1, OutputPage.class, data);