您会建议哪种压缩(GZIP是最受欢迎的)servlet过滤器?

2022-09-03 04:03:33

我正在寻找一个GZIP servlet过滤器,用于大容量的Web应用程序。我不想使用特定于容器的选项。

要求

  1. 能够压缩响应有效负载 (XML)
  2. 更快
  3. 在大批量应用的生产中久经考验
  4. 应正确设置适当的内容编码
  5. 可跨容器携带
  6. (可选)能够解压缩请求

谢谢。


答案 1

我用于压缩 Web 应用中的资源的 GZIP 筛选器:

public class CompressionFilter implements Filter {

    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String acceptEncoding = httpRequest.getHeader(HttpHeaders.ACCEPT_ENCODING);
        if (acceptEncoding != null) {
            if (acceptEncoding.indexOf("gzip") >= 0) {
                GZIPHttpServletResponseWrapper gzipResponse = new GZIPHttpServletResponseWrapper(httpResponse);
                chain.doFilter(request, gzipResponse);
                gzipResponse.finish();
                return;
            }
        }
        chain.doFilter(request, response);
    }

    public void init(FilterConfig filterConfig) throws ServletException {
    }

}

public class GZIPHttpServletResponseWrapper extends HttpServletResponseWrapper {

    private ServletResponseGZIPOutputStream gzipStream;
    private ServletOutputStream outputStream;
    private PrintWriter printWriter;

    public GZIPHttpServletResponseWrapper(HttpServletResponse response) throws IOException {
        super(response);
        response.addHeader(HttpHeaders.CONTENT_ENCODING, "gzip");
    }

    public void finish() throws IOException {
        if (printWriter != null) {
            printWriter.close();
        }
        if (outputStream != null) {
            outputStream.close();
        }
        if (gzipStream != null) {
            gzipStream.close();
        }
    }

    @Override
    public void flushBuffer() throws IOException {
        if (printWriter != null) {
            printWriter.flush();
        }
        if (outputStream != null) {
            outputStream.flush();
        }
        super.flushBuffer();
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (printWriter != null) {
            throw new IllegalStateException("printWriter already defined");
        }
        if (outputStream == null) {
            initGzip();
            outputStream = gzipStream;
        }
        return outputStream;
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        if (outputStream != null) {
            throw new IllegalStateException("printWriter already defined");
        }
        if (printWriter == null) {
            initGzip();
            printWriter = new PrintWriter(new OutputStreamWriter(gzipStream, getResponse().getCharacterEncoding()));
        }
        return printWriter;
    }

    @Override
    public void setContentLength(int len) {
    }

    private void initGzip() throws IOException {
        gzipStream = new ServletResponseGZIPOutputStream(getResponse().getOutputStream());
    }

}

public class ServletResponseGZIPOutputStream extends ServletOutputStream {

    GZIPOutputStream gzipStream;
    final AtomicBoolean open = new AtomicBoolean(true);
    OutputStream output;

    public ServletResponseGZIPOutputStream(OutputStream output) throws IOException {
        this.output = output;
        gzipStream = new GZIPOutputStream(output);
    }

    @Override
    public void close() throws IOException {
        if (open.compareAndSet(true, false)) {
            gzipStream.close();
        }
    }

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

    @Override
    public void write(byte[] b) throws IOException {
        write(b, 0, b.length);
    }

    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        if (!open.get()) {
            throw new IOException("Stream closed!");
        }
        gzipStream.write(b, off, len);
    }

    @Override
    public void write(int b) throws IOException {
        if (!open.get()) {
            throw new IOException("Stream closed!");
        }
        gzipStream.write(b);
    }

}

您还需要在 Web 中定义映射.xml:

<filter>
    <filter-name>CompressionFilter</filter-name>
    <filter-class>com.my.company.CompressionFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CompressionFilter</filter-name>
    <url-pattern>*.js</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>CompressionFilter</filter-name>
    <url-pattern>*.css</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>CompressionFilter</filter-name>
    <url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>CompressionFilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
</filter-mapping>

答案 2

据我所知,大多数人通常使用gzip压缩过滤器。通常来自ehcache

GZIP过滤器的实现是:net.sf.ehcache.constructs.web.filter.GzipFilter

将其包含在项目中的 Maven 坐标为:

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache-web</artifactId>
    <version>2.0.4</version>
</dependency>

您还需要指定 SLF4J 日志记录目标。如果你不知道这是什么,或者不在乎slf4j-jdk14或slf4j-simple works:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.6.4</version>
</dependency>

推荐