近期迷恋上httpclient模拟各种网站登陆,浏览器中的开发者工具中查看请求头信息,然后照葫芦画瓢写到httpclient的请求中去,requestheader中有这么一段设置:
Accept-Encoding gzip,deflate
之前模拟其他网站的时候这块并没有太在意,因为无论我在httpclient中添加上这段还是不添加,请求网站数据都没有任何影响,也不影响网站的安全检测,所以当时也就没有特别关注这个设置,直到模拟登陆58同城网站的时候第一次遇到这个问题,当添加上以上的这行请求头设置的时候,返回的网页数据是乱码,而且是那种各种粗体方块的乱码,经验告诉我这种乱码表现并不是简单的编码错误造成的,因为至少英文不应该出现乱码..而且如果是简单的gbk,utf-8之间的乱码也不会出现这种大面积的粗体方块..
然后想到这个Accept-Encoding,百度后知道,这个是用来设置从网站中接收的返回数据是否进行gzip压缩.这也就解释了为何返回的数据是大面积的粗体方块乱码,因为是压缩过的数据,也就不可能进行正常解码.
http://blog.csdn.net/zhangxinrun/article/details/5711307 这是一篇介绍gzip,deflate具体含义的博文
防止链接失效我直接摘抄一段:
gzip是一种数据格式,默认且目前仅使用deflate算法压缩data部分;deflate是一种压缩算法,是huffman编码的一种加强。deflate与gzip解压的代码几乎相同,可以合成一块代码。区别仅有:deflate使用inflateInit(),而gzip使用inflateInit2()进行初始化,比 inflateInit()多一个参数: -MAX_WBITS,表示处理raw deflate数据。因为gzip数据中的zlib压缩数据块没有zlib header的两个字节。使用inflateInit2时要求zlib库忽略zlib header。在zlib手册中要求windowBits为8..15,但是实际上其它范围的数据有特殊作用,见zlib.h中的注释,如负数表示raw deflate。Apache的deflate变种可能也没有zlib header,需要添加假头后处理。即MS的错误deflate (raw deflate).zlib头第1字节一般是0x78, 第2字节与第一字节合起来的双字节应能被31整除,详见rfc1950。例如Firefox的zlib假头为0x7801,python zlib.compress()结果头部为0x789c。deflate 是最基础的算法,gzip 在 deflate 的 raw data 前增加了 10 个字节的 gzheader,尾部添加了 8 个字节的校验字节(可选 crc32 和 adler32) 和长度标识字节。
问题到这里看似已经清晰了,但是依然有一个疑点,就是我之前模拟登陆网站的时候一直会设置这个header请求头,但是返回的数据却不是压缩过的.这看起来有些矛盾,经过进一步收集资料得知,浏览器中的都是会自动进行解压缩的,故请求头中都会加入这么一个编码设置,并且网站的服务端并不是都支持这个请求头参数,也就是说即便在请求头中加入这么一个压缩设置,服务器端返回数据的时候也不一定会进行压缩才返回..至此疑问都清除..
然后接下来就好办了,既然知道了问题的原因,那么我们用httpclient进行接收的时候也就好处理了,如果对方支持gzip压缩处理且我们的请求头中也加入的gzip压缩请求头,那么返回header中会有这么一个返回头信息:
Content-Encoding gzip
我们在接收返回信息的时候只需要稍微检测一下返回头中是否含有以上信息就可以进行相应的处理了,一段示例代码如下:
HttpResponse rep = client.execute(post);Header[] headers = rep.getHeaders("Content-Encoding");boolean isGzip = false;for(Header h:headers){ if(h.getValue().equals("gzip")){
//返回头中含有gzip isGzip = true; }}String responseString = null;if(isGzip){
//需要进行gzip解压处理 responseString = EntityUtils.toString(new GzipDecompressingEntity(rep.getEntity()));}else{ responseString = EntityUtils.toString(rep.getEntity());}
至此那个让人抓狂的粗体方块乱码问题解决完毕..