设置Accept-Encoding为gzip,deflate,返回的网页是乱码
用C#写代码去获取网页内容。
其中request的header中,设置Accept-Encoding为gzip,deflate:
req = (HttpWebRequest)WebRequest.Create(gSkydriveUrl);
req.Headers.Add("Accept-Encoding", "gzip,deflate");
结果始终返回是乱码:
其中,此处之所以加此header,是因为看到网页分析工具中所得到的浏览器浏览该网页,对应的http的header的内容中,就是这样设置的。
所以,代码中,也是模拟浏览器去访问网页,就设置了对应的Accept-Encoding为gzip,deflate了。
【解决过程】
1.刚开始以为是编码的问题,所以去尝试了不同的编码:
req.Headers["Accept-Charset"] = "GBK,utf-8;q=0.7,*;q=0.3";
req.Headers["Accept-Charset"] = "utf-8";
结果始终无法解决问题。
2.后来无意间,把Accept-Encoding取消了,没有设置为gzip,deflate:
//req.Headers.Add("Accept-Encoding", "gzip,deflate");
结果,获得的网页,就正常了。
3.后来网上找到了具体的解释,那就是,
普通浏览器访问网页,之所以添加:
"Accept-Encoding" = "gzip,deflate"
那是因为,浏览器对于从服务器中返回的对应的gzip压缩的网页,会自动解压缩,所以,其request的时候,添加对应的头,表明自己接受压缩后的数据。
而此代码中,如果也添加此头信息,结果就是,返回的压缩后的数据,没有解码,而将压缩后的数据当做普通的html文本来处理,当前显示出来的内容,是乱码了。
【后记 2012-02-14】
后来调试过程中,突然发现,原来对于HttpWebRequest的参数设置中,还有一个选项是AutomaticDecompression,对于新创建的HttpWebRequest:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url); |
其默认值是None,然后去试了试,该设置为Gzip,然后同时Accept-Encoding为对应的gzip:
req.Headers["Accept-Encoding"] = "gzip,deflate"; req.AutomaticDecompression = DecompressionMethods.GZip; |
结果证明,这样也是可以获得对应的格式正确的数据,而不是乱码的。
这就意味着,如果你获取网页内容太大的话,那么还是可以用这个办法的,这样就可以让HttpWebRequest自动帮你实现对应的解压缩了,可以减少数据数据传输量,节省时间,提高效率。
需要注意的是,我这里的实测结果,如果是请求的网页返回的内容不多的话,比如只有几K,那么用了此自动解压缩的设置,也没啥效率的提高,因为毕竟自动解压,也是要花时间的。所以,就是个权衡问题了。自己以实测结果为准,觉得是否采用自动解压。
【总结】
想要获得正确网页内容,而非乱码的话,就有两种方式了:
1.不要设置Accept-Encoding的Header
//req.Headers.Add("Accept-Encoding", "gzip,deflate");
2.设置Accept-Encoding的Header,同时设置对应的自动解压缩的模式
req.Headers["Accept-Encoding"] = "gzip,deflate";
req.AutomaticDecompression = DecompressionMethods.GZip;
具体采用哪种方法,自己根据需要选择。
httpclient访问网站时设置Accept-Encoding为gzip,deflate返回的结果为乱码的问题
近期迷恋上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());
}
至此那个让人抓狂的粗体方块乱码问题解决完毕..