HTML压缩(JSP的GZIP实现)【转】

背景:

HTTP压缩可以大大提高浏览网站的速度,它的原理是,在客户端请求网页后,从服务器端将网页文件压缩,再下载到客户端,由客户端的浏览器负责解压缩并浏览。相对于普通的浏览过程HTML,CSS,Javascript,Text,它可以节省40%左右的流量。更为重要的是,它可以对动态生成的,包括CGI、PHP,JSP,ASP,Servlet,SHTML等输出的网页也能进行压缩,压缩效率惊人。

目前实现gzip压缩有2种办法:

方法一、是有的容器(服务器)提供的功能,但这个局限于特定容器。比如apache+tomcat或者resin-pro版。

方法二、是部署前手动gzip压缩,配合servlet过滤器使用,这个能实现gzip功能,但是降低了灵活性。

方案一

1、TOMCAT配置GZIP压缩:

tomcat5.5.x配置

修改%TOMCAT_HOME%\conf\server.xml启用支持gzip压缩.

添加下列属性

compression="on"

compressionMinSize="2048"

noCompressionUserAgents="gozilla,traviata"

compressableMimeType="text/html,text/xml"

TOMCAT配置说明

1)compression="on"打开压缩功能

2)compressionMinSize="2048"启用压缩的输出内容大小,这里面默认为2KB

3)noCompressionUserAgents="gozilla,traviata"对于以下的浏览器,不启用压缩

4)compressableMimeType="text/html,text/xml" 压缩类型

Resin容器中配置GZIP压缩方法

http://localhost:8080/MyProj/pdf/0.jpg可以打开一张图片。用Httpwatch查看

Accept-Encoding:gzip,deflate

Sent:315

Received43106

开始配置Resin

我按照这样的配置:

<web-appid="/"root-directory="webapps/MyProj">

<filterfilter-name="gzip"filter-class="com.caucho.filters.GzipFilter">

<init>

<use-vary>true</use-vary>

</init>

</filter>

<filter-mappingfilter-name="gzip">

<url-pattern>

<exclude-pattern>*.jpg</exclude-pattern>

<include-pattern>/*</include-pattern>

</url-pattern>

</filter-mapping>

</web-app>

再测试发现不起作用!不清楚如何配置哦!

我再看了一下资料上面有讲说需要resin的专业版即resin-pro

现在再看下我的resin:Resin-3.2.1(builtFri,17Oct200804:11:01PDT)

果然是我的版本不一致导致的。重新从网上下载一下专业版的RESIN下来再试!

以下是我再测试的过程:

测试发现还是不行呀!我昏~~~不过感觉专业版与普通版在配置上面还是有点差别的

待续未完!

方案二:

设置Content-Encoding

Content-Encoding文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE4、IE5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面。

压缩流

publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)

throwsIOException,ServletException{

OutputStreamout=null;

Stringencoding=request.getHeader("Accept-Encoding"); 

if(encoding!=null&&encoding.indexOf("gzip")!=-1){

request.setHeader("Content-Encoding","gzip");  

out=newGZIPOutputStream(request.getOutputStream());

} 

elseif(encoding!=null&&encoding.indexOf("comdivss")!=-1){

request.setHeader("Content-Encoding","comdivss");  

out=newZIPOutputStream(request.getOutputStream());

}else{  

out=request.getOutputStream();

实例:

采用gzipservletfilter实现

从HTTP/1.1开始,客户端就可以在请求头中添加

Accept-Encoding:gzip,deflate(可以从HTTPWATCH中查看发现确实支持)

来向请求的服务器表明自己支持Gzip压缩的响应。Web服务器则在响应头中添加

Content-Encoding:gzip

来向客户端表明响应体是经过gzip压缩的。

程序代码如下:

(在此非常感谢http://tdcq.javaeye.com/blog/453644提供代码)

具体代码如下:

packagesh.blog.util.web.filter;

importjava.io.IOException;

importjava.util.zip.GZIPOutputStream;

importjavax.servlet.ServletOutputStream;

publicclassCompressedStreamextendsServletOutputStream{

privateServletOutputStreamout;

privateGZIPOutputStreamgzip;

/**

*指定压缩缓冲流

*@param输出流到压缩

*@throwsIOExceptionifanerroroccurswiththe{@linkGZIPOutputStream}.

*/

publicCompressedStream(ServletOutputStreamout)throwsIOException{

this.out=out;

reset();

}

/**@seeServletOutputStream**/

publicvoidclose()throwsIOException{

gzip.close();

}

/**@seeServletOutputStream**/

publicvoidflush()throwsIOException{

gzip.flush();

}

/**@seeServletOutputStream**/

publicvoidwrite(byte[]b)throwsIOException{

write(b,0,b.length);

}

/**@seeServletOutputStream**/

publicvoidwrite(byte[]b,intoff,intlen)throwsIOException{

gzip.write(b,off,len);

}

/**@seeServletOutputStream**/

publicvoidwrite(intb)throwsIOException{

gzip.write(b);

}

publicvoidreset()throwsIOException{

gzip=newGZIPOutputStream(out);

}

}

packagesh.blog.util.web.filter;

importjava.io.IOException;

importjava.io.PrintWriter;

importjavax.servlet.ServletOutputStream;

importjavax.servlet.http.HttpServletResponse;

importjavax.servlet.http.HttpServletResponseWrapper;

publicclassCompressionResponseextendsHttpServletResponseWrapper{

protectedHttpServletResponseresponse;

privateServletOutputStreamout;

privateCompressedStreamcompressedOut;

privatePrintWriterwriter;

protectedintcontentLength;

publicCompressionResponse(HttpServletResponseresponse)throwsIOException{

super(response);

this.response=response;

compressedOut=newCompressedStream(response.getOutputStream());

}

publicvoidsetContentLength(intlen){

contentLength=len;

}

publicServletOutputStreamgetOutputStream()throwsIOException{

if(null==out){

if(null!=writer){

thrownewIllegalStateException("getWriter()hasalreadybeencalledonthisresponse.");

}

out=compressedOut;

}

returnout;

}

publicPrintWritergetWriter()throwsIOException{

if(null==writer){

if(null!=out){

thrownewIllegalStateException("getOutputStream()hasalreadybeencalledonthisresponse.");

}

writer=newPrintWriter(compressedOut);

}

returnwriter;

}

publicvoidflushBuffer(){

try{

if(writer!=null){

writer.flush();

}elseif(out!=null){

out.flush();

}

}catch(IOExceptione){

e.printStackTrace();

}

}

publicvoidreset(){

super.reset();

try{

compressedOut.reset();

}catch(IOExceptione){

thrownewRuntimeException(e);

}

}

publicvoidresetBuffer(){

super.resetBuffer();

try{

compressedOut.reset();

}catch(IOExceptione){

thrownewRuntimeException(e);

}

}

publicvoidclose()throwsIOException{

compressedOut.close();

}

}

packagesh.blog.util.web.filter;

importjava.io.IOException;

importjava.util.Enumeration;

importjavax.servlet.Filter;

importjavax.servlet.FilterChain;

importjavax.servlet.FilterConfig;

importjavax.servlet.ServletException;

importjavax.servlet.ServletRequest;

importjavax.servlet.ServletResponse;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importorg.apache.commons.logging.Log;

importorg.apache.commons.logging.LogFactory;

publicclassCompressionFilterimplementsFilter{

protectedLoglog=LogFactory.getFactory().getInstance(this.getClass().getName());

@SuppressWarnings("unchecked")

publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,

FilterChainchain)throwsIOException,ServletException{

booleancompress=false;

if(requestinstanceofHttpServletRequest){

HttpServletRequesthttpRequest=(HttpServletRequest)request;

Enumerationheaders=httpRequest.getHeaders("Accept-Encoding");

while(headers.hasMoreElements()){

Stringvalue=(String)headers.nextElement();

if(value.indexOf("gzip")!=-1){

compress=true;

}

}

}

if(compress){//如果浏览器支持则压缩

HttpServletResponsehttpResponse=(HttpServletResponse)response;

httpResponse.addHeader("Content-Encoding","gzip");

CompressionResponsecompressionResponse=newCompressionResponse(httpResponse);

chain.doFilter(request,compressionResponse);

compressionResponse.close();

}

else{//如果浏览器不支持则不压缩

chain.doFilter(request,response);

}

}

publicvoidinit(FilterConfigconfig)throwsServletException{

}

publicvoiddestroy(){

}

}

一共有三个CLASS文件!实现GZIP压缩输出响应

2.1对图片输出做压缩处理测试

建立目录pdf里面存储图片

第一步:不配置过滤器用HTTPWATCHE发现

image/jpeg:42891bytes,670x446pixels

第二步:配置Web.xml配置过滤器

<filter>

<filter-name>gzip</filter-name>

<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>gzip</filter-name>

<url-pattern>/pdf/*</url-pattern>

</filter-mapping>

再用HTTPWATCH查看发现

image/jpeg:42891bytes,gzipcompressedto42712bytes(0.417%saving),670x446pixels

实现了一次压缩处理输出!

PS:我再用png格式的图片做过一次测试发现一次可以实现GZIP压缩输出

结论:通过上面的过滤器能够实现对图片的压缩处理,提高响应速度!

2.2对音乐的压缩处理以MP3的输出为测试对象

建立目录music里面存储音乐

第一步:不配置过滤器发现

audio/mpeg:9001bytesofbinarydata

第二步:配置过滤器

<filter>

<filter-name>gzip</filter-name>

<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>gzip</filter-name>

<url-pattern>/music/*</url-pattern>

</filter-mapping>

再次查看发现:

audio/mpeg:,gzipcompressedto0bytes(0%saving)

结论:上面的算法对音乐文件不起压缩作用。感觉这种GZIP的算法应该是不同的格式算法不一样

2.3对JS文件压缩输出

第一步:不做压缩

4864

第二步:配置压缩

<filter>

<filter-name>gzip</filter-name>

<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>gzip</filter-name>

<url-pattern>/scripts/*.js</url-pattern>

</filter-mapping>

输出:

application/x-javascript:4636bytes,gzipcompressedto69bytes(98.5%saving)

查看发现JS的压缩是相当高的了!

结论:将JS存入指定的目录然后直接对此目录做GZIP压缩输出。可以看到效果是显著的!

通过做GZIP压缩输出之后可以减少网络带宽流量从而加快下载速度!

2.4对CSS文件压缩输出

第一步:没有压缩输出

text/css:413bytes

第二步:压缩

配置:

<filter>

<filter-name>gzip</filter-name>

<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>gzip</filter-name>

<url-pattern>/scripts/*.js</url-pattern>

<url-pattern>/style/*.css</url-pattern>

</filter-mapping>

结果:

text/css:413bytes,gzipcompressedto101bytes(75.5%saving)

结论:对CSS的压缩效果也是非常明显的哦!

2.5对HTML页面压缩输出

第一步:不压缩

text/html:2272bytes

第二步;压缩

<filter>

<filter-name>gzip</filter-name>

<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>gzip</filter-name>

<url-pattern>/scripts/*.js</url-pattern>

<url-pattern>/style/*.css</url-pattern>

<url-pattern>*.html</url-pattern>

</filter-mapping>

结果:

text/html:2272bytes,gzipcompressedto240bytes(89.4%saving)

结论:对HTML的压缩效果也是非常明显的哦!

2.6对JSP页面的压缩

第一步:未做压缩

text/html;charset=iso-8859-1:1008bytes

第二步:压缩输出

<filter>

<filter-name>gzip</filter-name>

<filter-class>sh.blog.util.web.filter.CompressionFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>gzip</filter-name>

<url-pattern>/scripts/*.js</url-pattern>

<url-pattern>/style/*.css</url-pattern>

<url-pattern>*.html</url-pattern>

<url-pattern>*.jsp</url-pattern>

</filter-mapping>

结果:页面无输出!

结论:

以上的算法可以应用于图片、HTML、CSS、JS的GZIP压缩输出。对于JSP页面无效!

应用:

将来可以在站点中编写此类过滤器,将页面内容尽可能地做GZIP输出提高下载的速度

相关推荐