`
walksing
  • 浏览: 211943 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

使用gzip优化web应用(filter实现)

阅读更多
2009-05-18
使用gzip优化web应用(filter实现)


      以前使用过filter,也就是屏蔽一下受限制的资源访问路径,解决下中文乱码问题,其实filter在优化web应用发面也有出色的应用,我们可以使用filter,结合gzip 压缩技术,解决web应用中网络传输数据量大的问题,一般使用了gzip压缩,网络的传输流量能减少40%作用,效果还是相当明显的.在工作中,gzip在企业级的应用中还不是很普遍,也许是程序员一开始想的就是sql优化,缓存等更直接有效的方式,而忽略了gzip压缩方法吧.



    

为什么要开启Gzip ?

gzip是http协议中使用的一种加密算法,客户端向web服务器端发出了请求后,通常情况下服务器端会将页面文件和其他资源,返回到客户端,客户端加载后渲染呈现,这种情况文件一般都比较大,如果开启Gzip ,那么服务器端响应后,会将页面,JS,CSS等文本文件或者其他文件通过高压缩算法将其压缩,然后传输到客户端,由客户端的浏览器负责解压缩与呈现。通常能节省40%以上的流量(一般都有60%左右),一些PHP,JSP文件也能够进行压缩。





那怎么开启呢?

Tomcat 开启Gzip :

1.找到Tomcat 目录下的conf下的server.xml,并找到如下信息

Connector port="8080" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true"
将它改成如下的形式(其实在上面代码的下面已经有了,将他们打开而已。):

<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 --> <Connector port="8080" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" compression="on" compressionMinSize="2048" noCompressionUserAgents="gozilla, traviata" compressableMimeType="text/html,text/xml" >
这样,就能够对html和xml进行压缩了,如果要压缩css 和 js,那么需要将

compressableMimeType=”text/html,text/xml”加入css和js:

<Connector port="8080" ......... compressableMimeType="text/html,text/xml,text/css,text/javascript" >
你甚至可以压缩图片:

compressableMimeType=”text/html,text/xml”加入css和js:

<Connector port="8080" ......... compressableMimeType="text/html,text/xml,text/css,text/javascript,image/gif,image/jpg" >


——开启后——–

开启后重启Tomcat ,通过浏览器查看headers信息就能看到是否开启(firebug中有),如果开启了,那么transfer-encoding就会是Gzip,否则就是chunked。



  以上方式依赖了tomcat服务器的特性,如果你服务器是iis或者websphere那么还有不同的配置方式,下面我们使用filter,在代码级别完成web应用的gzip压缩的开启.



   实现定制输出的关键是对HttpServletResponse 进行包装,截获所有的输出,等到过滤器链处理完毕后,再对截获的输出进行处理,并写入到真正的HttpServletResponse 对象中。JavaEE 框架已经定义了一个HttpServletResponseWrapper 类使得包装HttpServletResponse 更加容易。我们扩展这个HttpServletResponseWrapper,截获所有的输出,并保存到ByteArrayOutputStream 中



步骤:







1.Wrapper  用来包装HttpServletResponse 对象





Java代码
1.public class Wrapper extends HttpServletResponseWrapper  
2.{  
3.    public static final int OT_NONE = 0, OT_WRITER = 1, OT_STREAM = 2;  
4.    private int outputType = OT_NONE;  
5.    private ServletOutputStream output = null;  
6.    private PrintWriter writer = null;  
7.    private ByteArrayOutputStream buffer = null;  
8.    public Wrapper(HttpServletResponse resp) throws IOException {  
9.    super(resp);  
10.    buffer = new ByteArrayOutputStream();  
11.    }  
12.    public PrintWriter getWriter() throws IOException {  
13.    if(outputType==OT_STREAM)  
14.    throw new IllegalStateException();  
15.    else if(outputType==OT_WRITER)  
16.    return writer;  
17.    else {  
18.    outputType = OT_WRITER;  
19.    writer = new PrintWriter(new OutputStreamWriter(buffer, getCharacterEncoding()));  
20.    return writer;  
21.    }  
22.    }  
23.    public ServletOutputStream getOutputStream() throws IOException {  
24.    if(outputType==OT_WRITER)  
25.    throw new IllegalStateException();  
26.    else if(outputType==OT_STREAM)  
27.    return output;  
28.    else {  
29.    outputType = OT_STREAM;  
30.    output = new WrappedOutputStream(buffer);  
31.    return output;  
32.    }  
33.    }  
34.    public void flushBuffer() throws IOException {  
35.    if(outputType==OT_WRITER)  
36.    writer.flush();  
37.    if(outputType==OT_STREAM)  
38.    output.flush();  
39.    }  
40.    public void reset() {  
41.    outputType = OT_NONE;  
42.    buffer.reset();  
43.    }  
44.    public byte[] getResponseData() throws IOException {  
45.    flushBuffer();  
46.    return buffer.toByteArray();  
47. 
48.    }  
49.    class WrappedOutputStream extends ServletOutputStream {  
50.    private ByteArrayOutputStream buffer;  
51.    public WrappedOutputStream(ByteArrayOutputStream buffer) {  
52.    this.buffer = buffer;  
53.    }  
54.    public void write(int b) throws IOException {  
55.    buffer.write(b);  
56.    }  
57.    public byte[] toByteArray() {  
58.    return buffer.toByteArray();  
59.    }  
60.    }  
61.} 
public class Wrapper extends HttpServletResponseWrapper
{
public static final int OT_NONE = 0, OT_WRITER = 1, OT_STREAM = 2;
private int outputType = OT_NONE;
private ServletOutputStream output = null;
private PrintWriter writer = null;
private ByteArrayOutputStream buffer = null;
public Wrapper(HttpServletResponse resp) throws IOException {
super(resp);
buffer = new ByteArrayOutputStream();
}
public PrintWriter getWriter() throws IOException {
if(outputType==OT_STREAM)
throw new IllegalStateException();
else if(outputType==OT_WRITER)
return writer;
else {
outputType = OT_WRITER;
writer = new PrintWriter(new OutputStreamWriter(buffer, getCharacterEncoding()));
return writer;
}
}
public ServletOutputStream getOutputStream() throws IOException {
if(outputType==OT_WRITER)
throw new IllegalStateException();
else if(outputType==OT_STREAM)
return output;
else {
outputType = OT_STREAM;
output = new WrappedOutputStream(buffer);
return output;
}
}
public void flushBuffer() throws IOException {
if(outputType==OT_WRITER)
writer.flush();
if(outputType==OT_STREAM)
output.flush();
}
public void reset() {
outputType = OT_NONE;
buffer.reset();
}
public byte[] getResponseData() throws IOException {
flushBuffer();
return buffer.toByteArray();

}
class WrappedOutputStream extends ServletOutputStream {
private ByteArrayOutputStream buffer;
public WrappedOutputStream(ByteArrayOutputStream buffer) {
this.buffer = buffer;
}
public void write(int b) throws IOException {
buffer.write(b);
}
public byte[] toByteArray() {
return buffer.toByteArray();
}
}
}






2.过滤器



Java代码
1.public class GZipFilter implements Filter  
2.{  
3. 
4.    public void destroy()  
5.    {  
6.        // TODO Auto-generated method stub  
7.          
8.    }  
9. 
10.    public void doFilter(ServletRequest request, ServletResponse response,  
11.            FilterChain chain) throws IOException, ServletException   
12.            {  
13.            System.out.println("进入过滤器");  
14.            HttpServletResponse resp = (HttpServletResponse)response;  
15.            Wrapper wrapper = new Wrapper(resp);  
16.            chain.doFilter(request, wrapper);  
17.            byte[] gzipData = gzip(wrapper.getResponseData());  
18.            resp.addHeader("Content-Encoding", "gzip");  
19.            resp.setContentLength(gzipData.length);  
20.            ServletOutputStream output = response.getOutputStream();  
21.            output.write(gzipData);  
22.            output.flush();  
23.            }  
24. 
25.    public void init(FilterConfig arg0) throws ServletException  
26.    {  
27.        // TODO Auto-generated method stub  
28.          
29.    }  
30. 
31.    private byte[] gzip(byte[] data) {  
32.        ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240);  
33.        GZIPOutputStream output = null;  
34.        try {  
35.        output = new GZIPOutputStream(byteOutput);  
36.        output.write(data);  
37.        }  
38.        catch (IOException e) {}  
39.        finally {  
40.        try {  
41.        output.close();  
42.        }  
43.        catch (IOException e) {}  
44.        }  
45.        return byteOutput.toByteArray();  
46.        }  
47.      
48.} 
public class GZipFilter implements Filter
{

public void destroy()
{
// TODO Auto-generated method stub

}

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
{
System.out.println("进入过滤器");
HttpServletResponse resp = (HttpServletResponse)response;
Wrapper wrapper = new Wrapper(resp);
chain.doFilter(request, wrapper);
byte[] gzipData = gzip(wrapper.getResponseData());
resp.addHeader("Content-Encoding", "gzip");
resp.setContentLength(gzipData.length);
ServletOutputStream output = response.getOutputStream();
output.write(gzipData);
output.flush();
}

public void init(FilterConfig arg0) throws ServletException
{
// TODO Auto-generated method stub

}

private byte[] gzip(byte[] data) {
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240);
GZIPOutputStream output = null;
try {
output = new GZIPOutputStream(byteOutput);
output.write(data);
}
catch (IOException e) {}
finally {
try {
output.close();
}
catch (IOException e) {}
}
return byteOutput.toByteArray();
}

}











3.在web.xml中配置 GZipFilter,当我们访问应用中以.html结尾的资源的使用,服务器端就开启http gzip压缩,将压缩后的信息通过http 协议传递给浏览器.



  

Xml代码
1.<filter> 
2.        <filter-name>ecsideExport</filter-name> 
3.        <filter-class>cn.com.xinli.test.GZipFilter</filter-class> 
4.    </filter> 
5. <filter-mapping> 
6.             <filter-name>ecsideExport</filter-name> 
7.             <url-pattern>*.html</url-pattern> 
8.         </filter-mapping>   
9.     
<filter>
<filter-name>ecsideExport</filter-name>
<filter-class>cn.com.xinli.test.GZipFilter</filter-class>
</filter>
<filter-mapping>
             <filter-name>ecsideExport</filter-name>
             <url-pattern>*.html</url-pattern>
         </filter-mapping>




测试: 首先下载ieHttpHeader 插件.



测试地址:

http://localhost:9090/dwr/test.html



   1.未开启http gzip 压缩



GET /dwr/test.html HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: localhost:9090
Connection: Keep-Alive


HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: W/"5060-1242444154000"
Last-Modified: Sat, 16 May 2009 03:22:34 GMT
Content-Type: text/html
Content-Length: 5060
Date: Mon, 18 May 2009 12:29:49 GMT





   2.开启http gzip 压缩



GET /dwr/test.html HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: localhost:9090
Connection: Keep-Alive

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: W/"5060-1242444154000"
Last-Modified: Sat, 16 May 2009 03:22:34 GMT
Content-Encoding: gzip
Content-Type: text/html
Content-Length: 837
Date: Mon, 18 May 2009 12:27:33 GMT



效果是非常明显的..........
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics