Android在发送HTTP POST/PUT请求时的默认字符集-特殊字符问题

17

我已经配置了apache httpClient,如下所示:

HttpProtocolParams.setContentCharset(httpParameters, "UTF-8");
HttpProtocolParams.setHttpElementCharset(httpParameters, "UTF-8");
我还为所有的http post和put请求包含了"http头Content-Type: application/json; charset=UTF-8"。

我试图发送包含特殊字符的json主体的http post/put请求(例如通过谷歌拼音键盘输入的中文字符、符号等)。这些字符在日志中显示为乱码,但我认为这是因为DDMS不支持UTF-8,正如这个问题所描述的那样。
问题在于当服务器接收到请求时,有时候根本看不到这些字符(尤其是中文字符),或者当我们通过GET请求检索它时,它会变成无意义的垃圾。
我还尝试在一个字段中放置250个非ASCII字符,因为该特定字段应该能够容纳多达250个字符。然而,在服务器端验证失败,声称已超过250个字符的限制。 250个ASCII字符可以正常工作。
服务器人员声称他们支持UTF-8。他们甚至尝试模拟包含中文字符的post请求,并且数据被服务器成功接收。然而,这个人(一个中国人)使用安装了中文语言包的Windows计算机(我想,因为他可以在键盘上输入中文字符)。
我猜测Android客户端和由中国人制作的服务器使用的字符集不对齐。但我不知道哪一个是错误的,因为服务器人员声称他们支持UTF-8,而我们的rest客户端配置为支持UTF-8。
这让我想知道Android默认在所有文本输入中使用哪种字符集,以及它是否可以在程序中更改为不同的字符集。我试图找到有关如何在输入小部件上执行此操作的资源,但我没有找到任何有用的信息。
是否有办法为Android中的所有输入小部件设置字符集?或者我在REST客户端配置中漏掉了什么?或者,也许,服务器人员没有在他们的服务器上使用UTF-8,而是使用Windows字符集?

1
关于Java String类的默认字符集:它表示一个UTF-16格式的字符串...。还在这里讨论过(https://dev59.com/dHVD5IYBdhLWcg3wGXlI)和在这里(https://dev59.com/nmox5IYBdhLWcg3wpFv5)。 - JJD
4个回答

49

显然,我忘记将StringEntity的字符集设置为UTF-8了。这些代码解决了问题:

    httpPut.setEntity(new StringEntity(body, HTTP.UTF_8));
    httpPost.setEntity(new StringEntity(body, HTTP.UTF_8));

在使用Android客户端发送具有非ASCII字符的HTTP POST时,至少有两个级别可以设置字符集。

  1. REST客户端本身
  2. StringEntity

更新:正如Samuel在评论中指出的那样,现代的做法是使用ContentType,如下所示:

    final StringEntity se = new StringEntity(body, ContentType.APPLICATION_JSON);
    httpPut.setEntity(se);

1
它并不清楚httpPut是什么,以及它与post有什么关联。 - ılǝ
1
httpPut和httpPost是来自Android的apache http库中的HttpPut和HttpPost实例。http://developer.android.com/reference/org/apache/http/client/methods/package-summary.html - avendael
1
不,我只是在说明HttpPut和HttpPost对象应该明确设置其字符串实体的编码。通常,所有向服务器发送数据的Http方法(put、patch、post等)都应该明确设置它们的StringEntity编码,以避免我在原始问题中遇到的问题。 - avendael
2
你的解决方案绝对正确,而且节省了我很多时间,但它现在已经过时了。我建议使用设置ContentType的替代方法:即最终StringEntity se = new StringEntity(query, ContentType.APPLICATION_JSON); - Samuel EUSTACHI
1
经过几天的苦苦寻找,我终于找到了你的答案!ContentType.APPLICATION_JSON 对我来说完美无缺!非常感谢 @avendael。 - Eduardo Fabricio
显示剩余3条评论

13

我知道这篇文章有点老,但仍然提供一个解决方案:

以下是我的代码,用于向服务器发布UTF-8字符串(无论是xml soap还是json)。 我尝试了使用西里尔文,哈希值和其他一些特殊字符,并且它完美运行。 这是我在论坛中发现的许多解决方案的综合。

HttpParams httpParameters = new BasicHttpParams();
HttpProtocolParams.setContentCharset(httpParameters, HTTP.UTF_8);
HttpProtocolParams.setHttpElementCharset(httpParameters, HTTP.UTF_8);

HttpClient client = new DefaultHttpClient(httpParameters);
client.getParams().setParameter("http.protocol.version", HttpVersion.HTTP_1_1);
client.getParams().setParameter("http.socket.timeout", new Integer(2000));
client.getParams().setParameter("http.protocol.content-charset", HTTP.UTF_8);
httpParameters.setBooleanParameter("http.protocol.expect-continue", false);
HttpPost request = new HttpPost("http://www.server.com/some_script.php?sid=" + String.valueOf(Math.random()));
request.getParams().setParameter("http.socket.timeout", new Integer(5000));

List<NameValuePair> postParameters = new ArrayList<NameValuePair>();
// you get this later in php with $_POST['value_name']
postParameters.add(new BasicNameValuePair("value_name", "value_val"));

UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(postParameters, HTTP.UTF_8);
request.setEntity(formEntity);
HttpResponse response = client.execute(request);

in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String lineSeparator = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
    sb.append(line);
    sb.append(lineSeparator);
}
in.close();
String result = sb.toString();

我希望这段代码对某些人有所帮助。 :)


5

您需要将字符串实体的字符集设置为UTF-8:

StringEntity stringEntity = new StringEntity(urlParameters, HTTP.UTF_8);

2

您可以使用 curl 发送相同的数据来排除服务器问题。 如果它能够与 curl 一起正常工作,使用 --trace 检查输出。

确保以字节形式发送内容主体。将 Android 的 HTTP 请求与成功的 curl 请求的输出进行比较。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接