【问题标题】:Difference between Apache HTTP Client and Spring RestTemplateApache HTTP Client 和 Spring RestTemplate 的区别
【发布时间】:2015-12-19 22:47:31
【问题描述】:

我正在调用 Google Translate API,一个是通过 Apache HTTP 客户端,另一个是通过 Spring 的 RestTemplate,得到不同的结果。两者都在获取完全相同的 URL:

我想将“Professeur des écoles”从法语翻译成英语。

使用的网址是(为了便于阅读,分成两行):

private static String URL = "https://www.googleapis.com/language/translate/v2?
key=AIzaSyBNv1lOS...&source=fr&target=en&q=Professeur+des+%C3%A9coles";

阿帕奇:

@Test
public void apache() throws IOException {
    String response = Request.Get(URL).execute().returnContent().asString();
    System.out.println(response);
}

返回(正确):

{ “数据”: { “翻译”:[ { "translatedText": "学校老师" } ] } }

@Test
public void spring() {
    RestTemplate template = new RestTemplate();
    String response = template.getForObject(URL, String.class);
    System.out.println(response);
}

返回(不正确):

{ “数据”: { “翻译”:[ { "translatedText": "Professor + of +% C3% A9coles" } ] } }

我是否在 RestTemplate HTTP 标头配置中遗漏了什么?

【问题讨论】:

  • 首先要做的是弄清楚每个客户端在请求中究竟发送了什么。有不同的方法可以做到这一点 - 我要做的是使用 netcat 在你的机器上打开一个监听套接字,然后更改为 URL 使其指向 localhost - netcat 然后将逐字打印出 HTTP 请求。
  • 我的猜测是 Spring 客户端正在对编码的 'é' 字符做一些时髦的事情。当短语只有 ASCII 字符时它是否正常工作?
  • 是的 - 简单的 ASCII 对两者都适用 - 这与编码有关。
  • 检查两者的 http 标头,可以使用wireshark 或膜监视器代理或类似方法
  • 准确发布每个网址使用的网址。我怀疑 RestTemplate 只是对您已经编码的字符串进行 URL 编码,您应该将其传递给未编码的参数。

标签: java spring apache-httpclient-4.x resttemplate


【解决方案1】:

接受String URL 的RestTemplate 方法执行URL 编码。

对于每个 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)。

大概你已经提供了以下String 作为第一个参数

https://www.googleapis.com/language/translate/v2?key=MY_KEY&source=fr&target=en&q=Professeur+des+%C3%A9coles

必须对字符% 进行编码。您的q 参数值因此变为

Professeur%2Bdes%2B%25C3%25A9coles

如果你decode,则相当于

Professeur+des+%C3%A9coles

Google 的翻译服务不知道如何处理 %C3%A9coles

如文档所示

为了避免使用 URI 方法变体来提供(或重用) 以前编码的 URI。准备这样一个具有完全控制权的 URI 编码,考虑使用UriComponentsBuilder

不要使用接受String URL 的重载,而是自己构造一个URI 并使用它。


Apache 的 HttpComponents Fluent API 没有指定行为,但似乎 String 值按原样使用。

【讨论】:

  • 哦 - 我在构建 URL 时自己明确编码了查询参数。所以我得到了双重编码?
  • @Kong 基本上。 RestTemplate 对提供给它的任何字符串 URL 进行编码。 Apache 的 fluent API 没有。它采用原始字符串并假设您自己完成。
  • 感谢您前几天对 Jackson 问题的回答 - DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS 就像一个魅力!
  • 您曾经想离开硅谷并搬回欧洲 - 请联系我 - 我们可以为您提供非常有吸引力的报价(我是首席技术官,我们资金充足)。而且我每天花费 50% 的时间在编码上——显然很糟糕!
  • @kong 你太慷慨了。如果您愿意,请在 LinkedIn 上与我联系。 (我来自蒙特利尔:p)
猜你喜欢
  • 2015-10-07
  • 2020-03-30
  • 2016-11-09
  • 2021-08-07
  • 2021-10-08
  • 2020-07-09
  • 2011-02-07
  • 2021-05-28
  • 2010-09-07
相关资源
最近更新 更多