有问题请教:
我将一个file中的json字符串取出,实例化一个StringEntiry,将json字符串写入请求体中。然后无论我以哪种编码方式输出StringEntity中的content,其中的中文均为乱码“???”。 这是怎么回事?
总结:就是在传递的参数中设置,这个很重要
- entity = new StringEntity(data,"UTF-8");
今天用httpclient传输json数据,服务端接受数据 中文乱码,下面分别贴上修改前与修改后的代码以及原因分析
(1)修改前:
client端
[java] view plain copy
- public String sendHttpPost(String httpUrl, String data) {
- // 创建post请求
- HttpPost httpPost = new HttpPost(httpUrl);
- StringEntity entity;
- try {
- entity = new StringEntity(data);
- entity.setContentEncoding("UTF-8");
- entity.setContentType("application/json");
- httpPost.setEntity(entity);
- } catch (UnsupportedEncodingException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return sendHttpPost(httpPost);
- }
[java] view plain copy
- private String sendHttpPost(HttpPost httpPost) {
- CloseableHttpClient httpClient = null;
- CloseableHttpResponse response = null;
- HttpEntity entity = null;
- String responseContent = null;
- // 创建默认的httpclient实例
- httpClient = HttpClients.createDefault();
- httpPost.setConfig(requestConfig);
- httpPost.setHeader("Accept","aplication/json");
- httpPost.addHeader("Content-Type","application/json;charset=UTF-8");
- // 执行请求
- try {
- logger.info("开始同步数据");
- response = httpClient.execute(httpPost);
- entity = response.getEntity();
- responseContent = EntityUtils.toString(entity, "UTF-8");
- logger.info("数据同步结果:" + responseContent);
- } catch (IOException e) {
- logger.error("同步数据出错:" + e.toString());
- e.printStackTrace();
- } finally {
- try {
- if (response != null) {
- response.close();
- }
- if (httpClient != null) {
- httpClient.close();
- }
- } catch (Exception e2) {
- logger.error("流关闭出错:" + e2.toString());
- }
- }
- return responseContent;
- }
(2)修改后
client端
[java] view plain copy
- public String sendHttpPost(String httpUrl, String data) {
- // 创建post请求
- HttpPost httpPost = new HttpPost(httpUrl);
- StringEntity entity;
- entity = new StringEntity(data,"UTF-8");
- entity.setContentType("application/json");
- //entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));//用这个跟上面一行那个结果一样,可以查看源码
- httpPost.setEntity(entity);
- return sendHttpPost(httpPost);
- }
- private String sendHttpPost(HttpPost httpPost) {
- CloseableHttpClient httpClient = null;
- CloseableHttpResponse response = null;
- HttpEntity entity = null;
- String responseContent = null;
- // 创建默认的httpclient实例
- httpClient = HttpClients.createDefault();
- httpPost.setConfig(requestConfig);
- httpPost.setHeader("Accept","aplication/json");
- httpPost.addHeader("Content-Type","application/json;charset=UTF-8");
- }
服务端 代码
[java] view plain copy
- //服务端 代码 通过红色字体的代码接受数据
- public Map<String, Object> getRequestPostParams(HttpServletRequest request) throws BusinessException {
- try {
- //接收数据
- StringBuffer sb = new StringBuffer() ;
- InputStream is = request.getInputStream();
- InputStreamReader isr = new InputStreamReader(is, "utf-8");
- BufferedReader br = new BufferedReader(isr);
- String s = "" ;
- while((s=br.readLine())!=null){
- sb.append(s) ;
- }
- String strData = sb.toString();
- if (null == strData || "".equals(strData)) {
- return new HashMap<String, Object>();
- }
- Map<String, Object> params = this.parseJSON2Map(strData);
- return params;
- } catch(Exception e) {
- throw new BusinessException(BusinessException.ERROR_INNER, "参数转换错误!");
- }
- }
下面来解释原因:
看到这里 发现了client端的不同的吧,没错 只有一行代码不一样
[java] view plain copy
- entity = new StringEntity(data,"UTF-8");
就是这行代码,因为构造方法的不同造成的
本来参考了 http://www.cnblogs.com/soundcode/p/6560947.html这个博客的文章把问题解决了,但是我发现 我自己的代码明明也设置额编码 为什么会出现乱码呢,于是我就去看源代码的实现,差异在哪里? 下面贴上源代码
[java] view plain copy
- public StringEntity(final String string, final ContentType contentType) throws UnsupportedCharsetException {
- super();
- Args.notNull(string, "Source string");
- Charset charset = contentType != null ? contentType.getCharset() : null;
- if (charset == null) {
- charset = HTTP.DEF_CONTENT_CHARSET;
- }
- try {
- this.content = string.getBytes(charset.name());
- } catch (final UnsupportedEncodingException ex) {
- // should never happen
- throw new UnsupportedCharsetException(charset.name());
- }
- if (contentType != null) {
- setContentType(contentType.toString());
- }
- }
然后就发现,在new StringEntity的时候,就已经将数据根据编码进行了处理,也就是说,如果你调用 new StringEntity(String string)此构造方法,就会使用其默认的编码进行转码(ISO-8859-1),无论你后面设置多少次(
[java] view plain copy
- entity.setContentEncoding("UTF-8");
或者
[java] view plain copy
- httpPost.addHeader("Content-Type","application/json;charset=UTF-8");
都不会改变字符串已经被按转码变成Byte[]数组的事实,当然在请求中设定传输编码格式还是要做的。
其实说这么多 ,解决问题的关键就一句话,在new StringEntity()的时候指定编码就解决了,因为在new的同时已经做了字符串的转码操作
之所以说这么多,是想告诉自己,问题解决了固然是好,但应该知道为什么这么做,多看源码,多问自己为什么,仅此共勉。
原文:http://blog.csdn.net/li_yan_fei/article/details/68064275