2

我创建了以下简单的测试来查询 iTunes:

@Test
fun loadArtist()
{
    val restTemplate = RestTemplate()

    val builder = UriComponentsBuilder.fromHttpUrl("https://itunes.apple.com/search")
    builder.queryParam("term", "howling wolf")
    builder.queryParam("entity", "allArtist")
    builder.queryParam("limit", 1)

    println("\n\nURL ${builder.toUriString()}")

    val result = restTemplate.getForObject(builder.toUriString(), String::class.java);
    println("Got artist: $result")
}

输出出乎意料:

URL https://itunes.apple.com/search?term=howling%20wolf&entity=allArtist&limit=1
Got artist: 

{
 "resultCount":0,
 "results": []
}

将生成的 URL 粘贴到浏览器中确实会产生预期的结果 - 艺术家返回。

https://itunes.apple.com/search?term=howling%20wolf&entity=allArtist&limit=1

此外,对查询进行硬编码也可以:

val result = restTemplate.getForObject("https://itunes.apple.com/search?term=howling%20wolf&entity=allArtist&limit=1", String::class.java);

. . 该问题似乎只发生在term包含空格的查询中。

什么地方出了错?除了手动组装 URL,如何修复?

4

1 回答 1

1

似乎是对空格进行双重编码的情况。来自 RestTemplate Javadoc:

对于每个 HTTP 方法,有三种变体:两种接受 URI 模板字符串和 URI 变量(数组或映射),而第三种接受 URI。请注意,对于 URI 模板,假定编码是必要的,例如 restTemplate.getForObject(" http://example.com/hotel list") 变为 " http://example.com/hotel%20list "。这也意味着如果 URI 模板或 URI 变量已经编码,将发生双重编码,例如http://example.com/hotel%20list变为 http://example.com/hotel%2520list)。为避免这种情况,请使用 URI 方法变体来提供(或重用)先前编码的 URI。要准备这样一个完全控制编码的 URI,请考虑使用 UriComponentsBuilder。

所以看起来 getForObject 实际上会查询https://itunes.apple.com/search?term=howling%2520wolf&entity=allArtist&limit=1并因此导致空结果。您总是可以在您的术语中用“+”替换空格,或者尝试让其中一个类跳过编码过程。

于 2015-12-16T13:36:26.547 回答