博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java Servlet GZip Servlet Filter 详解
阅读量:7106 次
发布时间:2019-06-28

本文共 6148 字,大约阅读时间需要 20 分钟。

GZip Servlet过滤器可用于GZip压缩内容从Java Web应用程序发送到浏览器。

###为什么要压缩

Gzip压缩HTML、js、css等,使得发送给浏览器的数据大小变得更小。提升上传速度,尤其是移动端带宽受限制的情况下,不过它可能带来服务器和浏览器的CPU消耗问题,但是响应速度会得道很大的改善。

###GZip 请求头

浏览器在发送到HTTP服务器(例如Java Web服务器)的请求中包含Accept-Encoding HTTP标头。 Accept-Encoding标头的内容告诉浏览器可以接受哪些内容编码。 如果该标题包含gzip值,则浏览器可以接受GZip压缩内容。 然后服务器可以将GZip压缩发送回浏览器的内容。

如果从服务器发回的内容是GZip压缩的,则服务器会在HTTP响应中包含带有值gzip的Content-Encoding HTTP标头。 这样浏览器就知道内容是GZip压缩的。

###为什么使用GZip Servlet过滤器?

如果对每一个Servlet请求都设置压缩,那肯定在性能上会有差距,所以Gzip Servlet过滤器 可以让我们对需要压缩的东西进行压缩,没必要压缩的就不去压缩。使性能最大化的提升。

###GZip Servlet滤波器设计

如图所示:首先需要一个Servlet过滤器类。 该类映射到web.xml文件中的一组URL。 当一个HTTP请求到达映射到过滤器的Servlet容器时,过滤器会在该请求被Servlet,JSP等处理之前截取请求所针对的目标。 GZip servlet过滤器检查客户端(浏览器)是否可以接受GZip压缩内容。如果可以接受,就对目标做压缩处理,然后将HttpServletResponse对象封装在GZipServletResponseWrapper进行压缩,最后将压缩内容写入HttpServletResponse。

###实例 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.

主要用到三个类:GzipServletFilter、GzipServletResponseWrapper、GzipServletOutputStream。

  • GZipServletFilter 用来拦截请求,检查浏览器是否接受压缩。它将在HttpServletResponse传递给过滤器链之前将信息包装在GZipServletResponseWrapper中。
  • GZipServletResponseWrapper 用来返回一个输出流给Servlet或者Jsp,可以是GZipServletOutputStream 或者PrintWriter 类型的数据。
  • GZipServletOutputStream 是用来压缩并写入的内容的,通过内部使用GZIPOutputStream来实现。

示例:

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.      //Hence no 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);  }}复制代码

###web.xml 配置

为了激活Gzip Servlet Filter,我们需要配置一些东西。

GzipFilter
com.xxx.GZipServletFilter
#这里填写自己的GzipServletFilter类路径。
GzipFilter
*.js
GzipFilter
*.css
GzipFilter
*.html
GzipFilter
*.jsp
GzipFilter
/
复制代码

转载地址:http://uhjhl.baihongyu.com/

你可能感兴趣的文章
更改具有Foreign key约束的表
查看>>
webpack缓存
查看>>
Java 运算符,条件结构小总结
查看>>
In-Memory:内存优化数据的持久化和还原
查看>>
字符串转换成整数
查看>>
hdu 5475(线段树)
查看>>
Java代码编写的30条建议
查看>>
标准的基于欧式距离的模板匹配算法优源码化和实现(附源代码)。
查看>>
对phpcms中{L('news')}的讲解
查看>>
博客园有感
查看>>
Hibernate三种状态
查看>>
设计模式C#实现(四)——迭代器模式
查看>>
MPAndroidChart的具体属性方法
查看>>
【vue】使用vue+element搭建项目,Tree树形控件使用
查看>>
博客作业2---线性表
查看>>
JAVA Day10
查看>>
leetcode394
查看>>
(18)odoo规范
查看>>
PHP:第一章——PHP中静态变量和常量
查看>>
软件过程与项目管理(第三次作业)
查看>>