HttpClient数据传输的编码方式

  • Post author:
  • Post category:其他


约定

1. HttpClient版本:HttpClient4.1

2. 服务端中间件:tomcat7

HttpGet请求的URI编码设置

1. 问题及原因

使用HttpClient的HttpGet方法进行get请求时,如果请求的URI中含有中文参数,则请求的服务端容易出现乱码问题。出现乱码的原因主要是因为请求URI中中文参数的编码和tomcat设置的编码不一致,导致乱码。

2. 解决方案

1) 设置tomcat编码

首先必须确定tomcat采用何种编码,才能确定请求的URI设置为何种编码。Tomcat的编码设置在tomcat的配置文件中设置,位置为: apache-tomcat-7.0.11\conf\server.xml,找到如下配置:

<Connector 
port="8181"
protocol="HTTP/1.1" 
connectionTimeout="20000" 
redirectPort="8443"  
URIEncoding="GB2312"/>

Tomcat默认是没有对URIEncoding进行配置,tomcat会采用默认的编码,一般是ISO-8859-1。

2) 设置URI编码

知道了tomcat(请求服务端)的编码方式,使用HttpGet请求时就需要对URI中的中文参数进行编码。上面设置了URIEncoding=”GB2312”,所以我们需要对中文参数进行GB2312的URI编码。例如:

HttpClient http = new DefaultHttpClient();
        String url = "http://127.0.0.1:8181/hello/httpclient?test=" + URLEncoder.encode("中文", "utf-8");
HttpGet get = new HttpGet(url);
HttpResponse response = http.execute(get);

这样服务端接收到HttpGet的请求,中文参数就不会出现乱码了。

HttpPost请求的URI及数据编码

1. 问题及原因

使用HttpClient的HttpPost方法进行Post请求时与Get不同的是,Post不仅有URI参数,还有请求body数据,如果这两种数据出现中文都有可能出现乱码。其中URI参数出现乱码的原因与上述Get方法出现乱码的原因相同,这里就不在叙述。Body数据出现乱码的原因则是请求数据的编码方式与服务端程序的解码方式不一致导致。

2. 解决方案

1) HttpClient端Post请求的编码设置

HttpClient http = new DefaultHttpClient();
String url = "http://127.0.0.1:8181/hello/httpclient?test=" + URLEncoder.encode("中文", "gb2312");
HttpPost post = new HttpPost(url);
JSONObject params = new JSONObject();
params.put("a", "测试1");
params.put("b", "测试2");
System.out.println(params.toString());
StringEntity entity = new StringEntity(params.toString(),"gb2312");
entity.setContentType("application/json;charset=gb2312");
post.setEntity(entity);
HttpResponse response = http.execute(post);

代码中

StringEntity entity = new StringEntity(params.toString(),"gb2312");

设置了以gb2312编码对数据进行编码。

如果不传入编码方式

new StringEntity(params.toString())

则会以默认的编码方式进行编码,一般是ISO-8859-1,这种编码无法表示中文字符,所以如果不进行设置,中文会出现乱码。

entity.setContentType("application/json;charset=gb2312");

设置请求的content-type,如果不设置,默认会根据

new StringEntity(params.toString(),"gb2312");

的编码方式来设置,text/plain;charset= gb2312

2) 服务端代码的解码

public void httpclientPost(HttpServletRequest req,HttpServletResponse resp) throws Exception {
        String a = req.getParameter("test");
        System.out.println("URI参数: test=" + a);
        System.out.println("req-content-type: " + req.getContentType() + "\ncharset: " + req.getCharacterEncoding());

        InputStream in = req.getInputStream();
        List<Byte> dataList = new ArrayList<Byte>();
        byte[] buffer = new byte[8*1024];
        while(in.read(buffer)>0){
            for(int i=0; i<buffer.length;++i){
                dataList.add(buffer[i]);
            }
        };
        byte[] data = new byte[dataList.size()+1];
        for(int i=0; i<dataList.size(); ++i){
            data[i] = dataList.get(i);
        }
System.out.println(new String(data,req.getCharacterEncoding()));
}

运行结果如下:

URI参数: test=中文
req-content-type: application/json;charset=gb2312
charset: gb2312
{"a":"测试1","b":"测试2"}
  • 1
  • 2
  • 3
  • 4

可以看到

new String(data,req.getCharacterEncoding())

这里使用请求中的数据编码方式来从数据流中生成对应的字符串,这样得到的中文数据就不会出现乱码了。

HttpClient请求响应数据中文乱码

1. 问题及原因

使用HttpClient的Get或Post方法请求得到的响应数据中的中文出现乱码。出现乱码的原因主要是因为对得到的响应数据解码方式和服务端的编码方式不一致。

2. 解决方案

1) 服务端设置返回数据的编码方式

public void httpclient(HttpServletRequest req,HttpServletResponse resp) throws Exception {
resp.setContentType("text/html;charset=gb2312");
        resp.setCharacterEncoding("gb2312");
        resp.getWriter().println("response返回中文");
}

setContentType与setCharacterEncoding都可以设置编码方式,但是必须调用setContentType来设置content-type,后面会说明原因。

2) HttpClient请求得到响应后解码

HttpResponse response = http.execute(get);
if (response.getStatusLine().getStatusCode() == 200) { 
    HttpEntity entity = response.getEntity();
    Header header = entity.getContentType();
    String strResp = EntityUtils.toString(response.getEntity());
    System.out.println(strResp);
}

这里的EntityUtils.toString()方法将得到的数据转换为字符串,那么就必须要考虑所使用的字符编码。如果在EntityUtils.toString()方法中没有显式的传入字符编码方式的参数,那么该方法就会根据response.getEntity()的ContentType的编码方式来进行解码。Header header = entity.getContentType();这个方法就可以获取entity的content-type。但是,如果服务端没有设置Content-Type,也就是在上面的服务端程序中没有调用setContentType()方法,那么这里获取的header将是null,也就是说无法获取到entity的Content-Type。那么EntityUtils.toString()方法也就无法知道服务端传过来的数据采用的何种编码方式,就会采用默认的ISO-8859-1编码方式进行转换,这样中文就会出现乱码。当然,也可以显式将编码方式传入EntityUtils.toString()函数中,但是必须确保传入的编码方式与服务端设置的返回数据的编码方式相同,EntityUtils.toString(response.getEntity(),”gb2312”);