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输出提高下载的速度