`
qtlkw
  • 浏览: 307197 次
  • 性别: 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

    Servlet Filter是Java Servlet API中的一个重要概念,它是Servlet容器(如Tomcat、Jetty等)提供的一种拦截请求和响应的能力,允许开发者在请求到达目标Servlet之前或之后进行处理。Filter可以用于实现诸如认证、...

    servlet之Filter使用范例--登陆验证

    Servlet是Java提供的一个用于扩展服务器功能的接口,而Filter则是一种动态web资源过滤机制,它允许我们在数据处理流程中进行预处理和后处理,比如登录验证、日志记录、GZIP压缩等。本篇文章将深入探讨如何使用Filter...

    简单使用Filter模拟Servlet中的过滤器

    在实际项目中,Filter的应用非常广泛,例如实现登录验证、字符集编码转换、GZIP压缩、安全控制等。通过理解和熟练使用Filter,开发者可以更好地控制和优化Web应用程序的行为。 由于提供的压缩包文件名为`webfilter`...

    Servlet之Filter深入讲解及实例研究

    Servlet之Filter是Java Web开发中的一个重要概念,它在Servlet规范中扮演着不可或缺的角色。Filter(过滤器)允许开发者在请求到达目标Servlet之前或之后对请求和响应进行处理,提供了诸如数据验证、日志记录、字符...

    servlet filter大全

    "servlet filter大全"这个主题涵盖了多种常见的过滤器设置,旨在提高应用的功能性和安全性。下面我们将详细探讨这些过滤器及其用途。 1. **字符集过滤器**: 这种过滤器的主要任务是确保请求和响应中的字符集正确...

    Servlet中的Filter

    Servlet中的Filter是Java Web开发中的一个重要组件,它主要用于在Servlet处理请求之前或之后对请求和响应进行拦截和处理。Filter不直接处理用户请求,而是通过Filter链的方式串联多个Filter,形成一个处理流程。 1....

    jsp,servlet,filter温故知新

    - **Filter**:在请求和响应之间添加额外的处理逻辑,如登录检查、GZIP压缩、字符编码转换等。 结合这三个技术,开发者可以构建出高效、可维护的Java Web应用。理解它们的工作原理和协同方式,对于提升Web开发技能...

    Javascript开发之js压缩篇.pdf

    作者提供了一个使用gzip servlet filter的示例代码,展示了如何使用gzip压缩来减少文件体积。 作者的解决方法可以分为两步:首先使用yui-compressor对js文件进行压缩混淆,然后使用gzip压缩来减少文件体积。这种...

    servlet+filter+lisenter 例子

    Filter接口的`doFilter()`方法是核心,它接收ServletRequest和ServletResponse对象,并通过FilterChain对象将请求传递到下一个Filter或目标Servlet。 监听器(Listener)是实现特定接口的Java类,它们用于监听和...

    servlet系列之Filter

    Filter不仅仅局限于字符编码和Session检查,它还可以用于日志记录、安全控制(如登录验证)、性能监控、GZIP压缩、URL重写等多种用途。通过组合和配置多个Filter,开发者可以构建出强大的中间件层,以满足复杂的...

    Servlet、Filter、Listener深入理解.docx

    Filter可以实现多个功能,如认证、日志、GZIP压缩等。关键方法包括: 1. `init(FilterConfig config)`: 初始化Filter,与Servlet的`init()`类似。 2. `doFilter(ServletRequest request, ServletResponse response...

    Servlet--2.filter

    GZIP压缩Filter可以提高响应的传输效率;字符编码Filter则可以确保请求和响应的数据正确编码。 6. **Spring MVC中的Filter**:在Spring框架中,Filter可以通过Spring的DelegatingFilterProxy与Spring的...

    超强过滤器彻底解决JSP-SERVLET中文参数GET-POST传递的问题(转)

    自定义的Filter需要实现`javax.servlet.Filter`接口,并重写`doFilter`方法。在这个方法中,首先检查请求的编码,如果没有设定或者不是预期的编码(如UTF-8),则设定正确的编码。这样,无论请求是GET还是POST,...

    java中servlet文字过滤器

    创建一个Servlet Filter,我们需要继承`javax.servlet.Filter`接口,并实现其`doFilter()`方法。在这个方法中,我们可以对请求和响应进行操作。例如,处理乱码问题,通常涉及编码转换。 ```java import javax....

    使用filter拦截servlet和jsp页面的内容,进行过滤后输出

    Filter是Java Servlet API的一部分,它允许开发者在请求到达目标Servlet或JSP之前以及响应离开Servlet之后对其进行处理。通过实现javax.servlet.Filter接口,我们可以定义自己的过滤规则,例如检查用户权限、字符...

    Servlet 的API文档

    1. `Filter`:可以拦截和修改请求或响应,实现过滤器功能,如登录检查、GZIP压缩等。 2. `FilterChain`:用于在多个Filter之间传递请求和响应。 六、Servlet生命周期 Servlet的生命周期包括加载、初始化、服务和...

    Servlet进阶的相关内容

    5. **Filter过滤器**:Servlet可以与Filter一起使用,Filter在Servlet处理请求之前和之后执行,可用于登录验证、GZIP压缩、字符编码转换等。 6. **异步处理**:Servlet 3.0引入了异步处理,允许在`service()`方法...

    servlet过滤器实现(Eclipse工程)

    Servlet过滤器是Servlet API的一部分,定义在`javax.servlet.Filter`接口中。它们的主要作用是拦截HTTP请求,对请求或响应进行预处理和后处理,比如登录检查、GZIP压缩、字符编码转换等。过滤器可以应用于整个Web...

Global site tag (gtag.js) - Google Analytics