解决乱码有如下几种方式,还有两种特殊的情况:
首先选用正确的post和get方式是必须的
如果出现乱码 可以尝试分别单独使用以下方法:
if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
entity = response.getEntity();
if (entity != null) {
//第一种方式
System.out.println(EntityUtils.toString(entity,"GBK"));
//第二种方式
String outstr = new String(EntityUtils.toString(entity).getBytes("ISO-8859-1"),"GBK");
System.out.println(outstr);
//第三种方式
String responseString = new String(EntityUtils.toString(entity));
responseString=new String(responseString.getBytes("ISO-8859-1"),"GBK");
System.out.println(responseString);
}
}
这三种方式都不起作用,一直乱码。
然后又找到另一种方式,在httpclient之前设置编码
client.getParams().setParameter("http.protocol.content-charset", "UTF-8");
this.response = client.execute(hp);
如果以上几种方式都没解决,那就可能是以下的两种特殊情况:
情况一: 编码被压缩了
在用httpclient做网页提取的过程中,通过抓包工具发现了 头部中会有 Accept-Encoding: gzip, deflate字段
如果头部有了该字段,则服务器会将内容reponse的内容进行压缩用gzip或者deflate算法,然后reponse给用户。目前我看到的仅仅有gzip算法被用到,然后返回给用户的数据也是压缩后的数据,这样往往可以减轻服务器的负担,同时也减少了网络传输
如果有了该字段,你又不处理,那么就会遇到乱码现象(这是肯定的,因为只是压缩过的数据)。下边我会利用httpclient工具对加入了Accept-Encoding: gzip, deflate 的内容进行处理,使得内容可以正常处理。
增加代码如下:
if (httpResponse.getStatusLine().getStatusCode() == 200) { HttpEntity httpEntity = httpResponse.getEntity(); if(httpEntity.getContentEncoding()!=null){ if("gzip".equalsIgnoreCase(httpEntity.getContentEncoding().getValue())){ httpEntity = new GzipDecompressingEntity(httpEntity); } else if("deflate".equalsIgnoreCase(httpEntity.getContentEncoding().getValue())){ httpEntity = new DeflateDecompressingEntity(httpEntity); }} result = EntityUtils.toString(httpEntity, encode);// 取出应答字符串 // System.out.println(result);}
第二种情况: 有时候我们使用System.out.println(EntityUtils.toString(entity,"GBK"))能解析大部分代码,但是还有小部分出现乱码
这种情况是因为 我们设置的编码没起作用
我们看httpcore-4.2.4.jar版本的EntityUtils源码
如下:
public static String toString( final HttpEntity entity, final String defaultCharset) throws IOException, ParseException { return toString(entity, defaultCharset != null ? Charset.forName(defaultCharset) : null); }
public static String toString( final HttpEntity entity, final Charset defaultCharset) throws IOException, ParseException { if (entity == null) { throw new IllegalArgumentException("HTTP entity may not be null"); } InputStream instream = entity.getContent(); if (instream == null) { return null; } try { if (entity.getContentLength() > Integer.MAX_VALUE) { throw new IllegalArgumentException("HTTP entity too large to be buffered in memory"); } int i = (int)entity.getContentLength(); if (i < 0) { i = 4096; } Charset charset = null; try { ContentType contentType = ContentType.get(entity); if (contentType != null) { charset = contentType.getCharset(); } } catch (final UnsupportedCharsetException ex) { throw new UnsupportedEncodingException(ex.getMessage()); } if (charset == null) { charset = defaultCharset; } if (charset == null) { charset = HTTP.DEF_CONTENT_CHARSET; } Reader reader = new InputStreamReader(instream, charset); CharArrayBuffer buffer = new CharArrayBuffer(i); char[] tmp = new char[1024]; int l; while((l = reader.read(tmp)) != -1) { buffer.append(tmp, 0, l); } return buffer.toString(); } finally { instream.close(); } }
发现它会先去获取一遍 网站头文件传回来的 编码 如果有编码就不用我们的编码
但是 我们有时候会遇到 网站的头文件 传回来的编码 是 gb2312 但其实网站用的是gbk
所以 我们要把以上方法重新,把 获取 头文件编码部分注释掉
我最后用的方法如下 :
result = enCodetoString(httpEntity, encode);// 取出应答字符串 public static String enCodetoString( final HttpEntity entity, final String defaultCharset) throws IOException, ParseException { return enCodetoStringDo(entity, defaultCharset != null ? Charset.forName(defaultCharset) : null); } public static String enCodetoStringDo( final HttpEntity entity, Charset defaultCharset) throws IOException, ParseException { if (entity == null) { throw new IllegalArgumentException("HTTP entity may not be null"); } InputStream instream = entity.getContent(); if (instream == null) { return null; } try { if (entity.getContentLength() > Integer.MAX_VALUE) { throw new IllegalArgumentException("HTTP entity too large to be buffered in memory"); } int i = (int)entity.getContentLength(); if (i < 0) { i = 4096; } Charset charset = null; try { // ContentType contentType = ContentType.get(entity); // if (contentType != null) { // charset = contentType.getCharset(); // } } catch (final UnsupportedCharsetException ex) { throw new UnsupportedEncodingException(ex.getMessage()); } if (charset == null) { charset = defaultCharset; } if (charset == null) { charset = HTTP.DEF_CONTENT_CHARSET; } Reader reader = new InputStreamReader(instream, charset); CharArrayBuffer buffer = new CharArrayBuffer(i); char[] tmp = new char[1024]; int l; while((l = reader.read(tmp)) != -1) { buffer.append(tmp, 0, l); } return buffer.toString(); } finally { instream.close(); } }
下面还有一个方法 可以检测字符的解析
System.out.println(Arrays.toString("堎".getBytes(Charset.forName("gbk")))); System.out.println(new String(new byte[]{-120, -39},Charset.forName("gb2312")));