`
qtlkw
  • 浏览: 300291 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

GZip Servlet Filter

    博客分类:
  • JAVA
 
阅读更多
A GZip Servlet Filter can be used to GZip compress content sent to a browser from a Java web application. This text will explain how that works, and contains a GZip Servlet Filter you can use in your own Java web applications. If you do not know what a Servlet filter is, read my text on Servlet Filters.

Table of contents:

    Why GZip Compress Content?
    GZip HTTP Headers
    Why a GZip HTTP Servlet Filter?
    GZip Servlet Filter Design
    GZip Servlet Filter Code
    GZip Servlet Filter web.xml Configuration

Why GZip Compress Content?

GZip compressing HTML, JavaScript, CSS etc. makes the data sent to the browser smaller. This speeds up the download. This is especially beneficial for mobile phones where internet bandwidth may be limited. GZip compressing content adds a CPU overhead on the server and browser, but it is still speeding up the total page load compared to not GZip compressing.
GZip HTTP Headers

The browser includes the Accept-Encoding HTTP header in requests sent to an HTTP server (e.g. a Java web server). The content of the Accept-Encoding header tells what content encodings the browser can accept. If that header contains the value gzip in it, the browser can accept GZip compressed content. The server can then GZip compress the content sent back to the browser.

If the content sent back from the server is GZip compressed, the server includes the Content-Encoding HTTP header with the value gzip in the HTTP response. That way the browser knows that the content is GZip compressed.
Why a GZip Servlet Filter?

You could implement GZip compression in each and every Servlet or JSP in your application if you wanted to. But that gets clumsy.

The smart thing about a GZip Servlet filter is that it is executed before and after any Servlet, JSP, or even static files. That way you can create a single servlet filter that enables GZip compression for all content that needs it. The Servlets, JSPs etc. don't even know that the content is being compressed, because it happens in the Servlet filter. The GZip Servlet filter enables GZip compression, sets the right HTTP headers, and makes sure that content written by Servlets, JSPs etc. is compressed.
GZip Servlet Filter Design

The design of a GZip servlet filter looks like this:
The GZip Servlet Filter design.
The GZip Servlet Filter design.

First you need a Servlet filter class. That class is mapped to a set of URL's in the web.xml file.

When an HTTP request arrives at the Servlet container which is mapped to the filter, the filter intercepts the request before it is handled by the Servlet, JSP etc. which the request is targeted at. The GZip servlet filter checks if the client (browser) can accept GZip compressed content. If yes, it enables compression of the response.

GZip compression of the response is enabled by wrapping the HttpServletResponse object in a GZipServletResponseWrapper. This wrapper is passed to the Servlet, JSP etc. which handles the request. When the Servlet, JSP etc. writes output to be sent to the browser, it does so to the response wrapper object. The Servlet, JSP etc. cannot see the difference between a real HttpServletResponse and the wrapper object. The response wrapper object then compresses the written content and writes the compressed content to the HttpServletResponse. Quite simple.
GZip Servlet Filter Code

Here is the GZip Servlet filter code. There are not really that many ways you can write it. It is pretty straightforward.

The code consists of 3 classes. A GZipServletFilter, a GZipServletResponseWrapper and a GZipServletOutputStream.

The GZipServletOutputStream is what compresses the content written to it. It does so by using a GZIPOutputStream internally, which is a standard Java class.

When the GZipServletResponseWrapper gives back an OutputStream or PrintWriter to a Servlet or JSP, it is either a GZipServletOutputStream or a PrintWriter that writes to the GZipServletOutputStream which is returned.

The GZipServletFilter is what intercepts the requests, checks if the client accepts compression or not, and enables compression if it does. It does so by wrapping the HttpServletResponse in a GZipServletResponseWrapper before passing it down the filter chain.

Here are all three classes:

public class GZipServletFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {

        HttpServletRequest  httpRequest  = (HttpServletRequest)  request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        if ( acceptsGZipEncoding(httpRequest) ) {
            httpResponse.addHeader("Content-Encoding", "gzip");
            GZipServletResponseWrapper gzipResponse =
                new GZipServletResponseWrapper(httpResponse);
            chain.doFilter(request, gzipResponse);
            gzipResponse.close();
        } else {
            chain.doFilter(request, response);
        }
    }

    private boolean acceptsGZipEncoding(HttpServletRequest httpRequest) {
        String acceptEncoding = httpRequest.getHeader("Accept-Encoding");
        return acceptEncoding != null && acceptEncoding.indexOf("gzip") != -1;
    }
}
   

class GZipServletResponseWrapper extends HttpServletResponseWrapper {

    private GZipServletOutputStream gzipOutputStream = null;
    private PrintWriter             printWriter      = null;

    public GZipServletResponseWrapper(HttpServletResponse response)
            throws IOException {
        super(response);
    }

    public void close() throws IOException {

        //PrintWriter.close does not throw exceptions. Thus, the call does not need
        //be inside a try-catch block.
        if (this.printWriter != null) {
            this.printWriter.close();
        }

        if (this.gzipOutputStream != null) {
            this.gzipOutputStream.close();
        }
    }


    /**
     * Flush OutputStream or PrintWriter
     *
     * @throws IOException
     */

    @Override
    public void flushBuffer() throws IOException {

        //PrintWriter.flush() does not throw exception
        if(this.printWriter != null) {
            this.printWriter.flush();
        }

        IOException exception1 = null;
        try{
            if(this.gzipOutputStream != null) {
                this.gzipOutputStream.flush();
            }
        } catch(IOException e) {
            exception1 = e;
        }

        IOException exception2 = null;
        try {
            super.flushBuffer();
        } catch(IOException e){
            exception2 = e;
        }

        if(exception1 != null) throw exception1;
        if(exception2 != null) throw exception2;
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (this.printWriter != null) {
            throw new IllegalStateException(
                "PrintWriter obtained already - cannot get OutputStream");
        }
        if (this.gzipOutputStream == null) {
            this.gzipOutputStream = new GZipServletOutputStream(
                getResponse().getOutputStream());
        }
        return this.gzipOutputStream;
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        if (this.printWriter == null && this.gzipOutputStream != null) {
            throw new IllegalStateException(
                "OutputStream obtained already - cannot get PrintWriter");
        }
        if (this.printWriter == null) {
            this.gzipOutputStream = new GZipServletOutputStream(
                getResponse().getOutputStream());
            this.printWriter      = new PrintWriter(new OutputStreamWriter(
                this.gzipOutputStream, getResponse().getCharacterEncoding()));
        }
        return this.printWriter;
    }


    @Override
    public void setContentLength(int len) {
        //ignore, since content length of zipped content
        //does not match content length of unzipped content.
    }
}


class GZipServletOutputStream extends ServletOutputStream {
    private GZIPOutputStream    gzipOutputStream = null;

    public GZipServletOutputStream(OutputStream output)
            throws IOException {
        super();
        this.gzipOutputStream = new GZIPOutputStream(output);
    }

    @Override
    public void close() throws IOException {
        this.gzipOutputStream.close();
    }

    @Override
    public void flush() throws IOException {
        this.gzipOutputStream.flush();
    }

    @Override
    public void write(byte b[]) throws IOException {
        this.gzipOutputStream.write(b);
    }

    @Override
    public void write(byte b[], int off, int len) throws IOException {
        this.gzipOutputStream.write(b, off, len);
    }

    @Override
    public void write(int b) throws IOException {
        this.gzipOutputStream.write(b);
    }
}
  

GZip Servlet Filter web.xml Configuration

In order to activate the GZip Servlet filter in your Java web application, you need the configuration below. Remember to replace the class name with the fully qualified name of your own GZip Servlet filter class. The filter mappings determine what HTTP requests the filter is activated for.

<filter>
    <filter-name>GzipFilter</filter-name>
    <filter-class>com.jenkov.tutorials.filters.gzip.GZipServletFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>*.js</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>*.css</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>GzipFilter</filter-name>
    <url-pattern>/</url-pattern>
</filter-mapping>
分享到:
评论

相关推荐

    servlet filter

    在com.tacitknowledge.filters开源项目上的扩展,修改了原项目的部分代码,其中配置文件名字应该在classes目录下filters_config.properties.其他的可以参照apidocs,如有bug可给我留言或者email:zhuyu4839@gmail.com

    一个可用的GZIP Filter和Cache Filter的jar包

    一个jar包,包含: 一个可用的GZIP Filter 一个可用的Cache Filter

    gzip.rar_C gzip源码_c语言gzip_gzip压缩_gzip解压_poetryfem

    使用C语言编写的GZIP压缩及解压源代码

    gzip的Windows版 gzip.exe

    gzip的Windows版,展开由gzip压缩的文件。gzip压缩文件有gzip.exe gzip.doc Readme Copying 四个子文件夹。 gzip 的Window版的gzip, 也就是gzip124xN.exe. 下载 gzip 的Window版的gzip, 也就是gzip124xN.exe。

    gzip源代码gzip源代码

    gzip源代码gzip源代码gzip源代码

    GZIP_gzip_

    Lossless compression algorithm GZIP related papers

    易语言GZIP解压缩

    易语言GZIP解压缩源码,GZIP解压缩,GZIP压缩,GZIP解压,InitDecompression,InitCompression,CreateDecompression,CreateCompression,ResetDecompression,ResetCompression,DestroyDecompression,DeInitCompression,...

    gzip源码,gzip压缩算法

    gzip源码,gzip压缩算法。GZIP学习

    易语言gzip解压缩模块

    易语言gzip解压缩模块源码,gzip解压缩模块,PeLoader_LoadLibrary,PeLoader_FreeLibrary,PeLoader_GetProcAddress,PeLoader_GetEntryPoint,Call,初始化,GZIP压缩,GZIP解压

    java实现gzip ajax请求gzip压缩

    java实现gzip ajax请求gzip压缩 等

    STM32移植gzip

    stm32f103ze移植gzip工程,带测试函数。由于gzip对内存要求较多,采用了外部SRAM。

    gzip源码 (可离线安装gzip)

    gzip源码 可以离线安装 gzip 工具 ,请参照压缩包里面的 REAME

    gzip gunzip源码下载以及编译,以及自定义交叉编译方法

    下载gzip-1.10.zip文件后,解压 unzip zip-1.10.zip cd zip-1.10 1.编译本机可用的gzip, ./configure CC="cc" make 该目录下生成可执行文件:gzip gunzip 2.若需要自定义交叉编译工具,解压代码后执行: ./...

    易语言GZIP数据解压缩

    易语言GZIP数据解压缩源码,GZIP压缩,GZIP解压,InitDecompression,InitCompression,CreateDecompression,CreateCompression,ResetDecompression,ResetCompression,DestroyDecompression,DeInitCompression,...

    图片base64、gzip编码及解码

    编码:图片经过base64编码,再进行gzip压缩。 解码:gzip解压,base64解码。

    GZIP压缩工具 下载

    GZIP压缩工具GZIP压缩工具GZIP压缩工具

    spring-gzip-filter:Spring GZIP过滤器

    弹簧-gzip-过滤器Spring GZIP过滤器已弃用Spring 1.2.2+ 默认通过application.properties启用压缩此实现提供了一个简单但功能强大的 servlet 过滤器,以自动为您的 Web 请求添加 GZIP 支持,它现在不是 100% 可定制...

    J2ME GZIP压缩开源包

    在平时的开发中,我们会碰到数据量过大的问题,为了解决这个问题,我们可以用GZIP处理方式,J2ME本身没有提供GZIP压缩,但可以利用一些开源包。 上面此句用于解压GZIP,至是否要转换成DataInputStream还是...

    利用JAVASCRIPT即你想那个GZIP压缩与解压缩

    利用JAVASCRIPT即你想那个GZIP压缩与解压缩 最近流行的网络游戏(FLASH)数据传输都是用GZIP进行压缩与解压缩的,在客户端FLASH对与服务器交互的数据进行解压缩,

    gzip安装文件gzip安装文件

    gzip安装文件,安装后将gzip.exe放置到system32文件夹下,配置环境变量即可使用。 gzip安装文件,安装后将gzip.exe放置到system32文件夹下,配置环境变量即可使用。

Global site tag (gtag.js) - Google Analytics