闲话少说,还是先来看一下为什么要使用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")) {
is= new 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) {
is= new GZIPInputStream(bis);
} else {
// 取前两个字节
is= bis;
}
至于如何绕过WAP的限制访问外网,请继续关注Android IT,我们会在后面做讲解。