喜糖

移动开发工程师 。涉及 android、ios、jni

导航

gzip相关【转帖】

Posted on 2012-08-15 18:28  喜糖  阅读(537)  评论(0编辑  收藏  举报

 

闲话少说,还是先来看一下为什么要使用GZip吧,HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来减少文件大小,减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。

1、那如何在HTTP请求中使用GZip呢?

一般来说,在HTTP连接中,并不是所有的接收者都支持GZip格式的,所以根据HTTP协议,如果你可以处理GZip格式,并且希望服务器以GZip的格式来返回内容,需要在HTTP的请求的Header中声明"Accept-Encoding"为"gzip",如果服务器可以将内容压缩为GZip格式,那么服务器返回的Response的Header中将会设置"Content-Encoding" 属性的值是gzip,同时将返回的内容压缩为GZip格式。

 

2、在Android代码中如何实现GZip呢?

首先要在Http请求中加入支持GZip格式的声明,不同HTTP连接对象的设置方式也不相同,我们以HttpGet来举例:

httpRequest = newHttpGet(url);

httpRequest.addHeader("Accept-Encoding""gzip"); 

接收到服务器的返回时,要根据Response的Header中"Content-Encoding" 的值来绝定是否需要解压GZip内容,Android的SDK中内置了GZIPInputStream可以帮助我们解压GZip流得到一个正常的输入流。

HttpEntity httpEntity = httpResponse.getEntity();

InputStream is= httpEntity.getContent();

 

if (httpEntity.getContentEncoding().getValue().contains("gzip")) {

        isnew GZIPInputStream(is);

}

 

OK,这样就可以实现了,简单吧,大家觉得有什么不对劲了吗?这么好用的一项功能难道这么简单就可以实现?没错,如果不是在天朝写成如此就已经可以了,但是在天朝,我们当然不会这么省心。

在我国移动运营商“创新性”地弄了一种名叫“WAP”的网络,在常规的状况下WAP网络下只能访问WAP的内网,这就是使用WAP接入点时所有国外的应用都无法使用的原因。WAP网络为我们带来了两个难题:1是如何在WAP网络中访问外网,2是WAP网络的路由器会对流经的数据进行处理,很奇怪对不对,就好像是我们往来的信件会被人偷看,不仅仅是偷看,它还会做修改呢,很多的HTTP请求中的Header会被过滤掉,gzip的头也在其中,路由器过滤掉gzip标示的同时会把内容解压,这样我们的gzip就不起作用了。

怎样可以绕过那些路由器的过滤呢?比较简单的一个方法是服务器的返回不遵守HTTP协议,内容使用GZip压缩,但是不返回Content-Encoding=gzip,这样路由器就没有办法了。

如果这样我们的程序也要进行一定的修改,因为不能判断Content-Encoding来解压GZip了。我们可以输入流读取前两个字节,如果是0x8B1F,就认为是GZip格式。但是InputStream读过一次流就无法使用了,虽然它有reset方法,但是不知为何不起作用。经过试验我们选择了使用BufferedInputStream来中转,因为它可以通过reset来重新定位到流的开头。

 

BufferedInputStream bis = new BufferedInputStream(is);

bis.mark(2);

// 取前两个字节

byte[] header = new byte[2];

int result = bis.read(header);

// reset输入流到开始位置

bis.reset();

// 判断是否是GZIP格式

if(result!=-1 && getShort(header, 0)==0x8b1f) {

        isnew GZIPInputStream(bis);

else {

        // 取前两个字节

        is= bis;

}

至于如何绕过WAP的限制访问外网,请继续关注Android IT,我们会在后面做讲解。