Tomcat gzip优化:提前将体积大的静态文件进行GZIP压缩

提出问题

如果静态文件比较大(比如超过 1M),如果让 tomcat 进行 gzip 压缩,需要消耗 CPU,尤其是访问量较大

如何避免消耗 CPU

分析

  1. 提前将 体积大 的静态文件,进行 gzip 压缩

  2. 当浏览器发请求时,由 过滤器 拦截,发现读取该文件,就不用 tomcat处理,而是由 过滤器 读取 gzip 文件,并发送给浏览器

解决

代码

import java.io.ByteArrayOutputStream;  
import java.io.IOException;  
import java.io.InputStream;  
import java.util.logging.Logger;  

import javax.servlet.Filter;  
import javax.servlet.FilterChain;  
import javax.servlet.FilterConfig;  
import javax.servlet.ServletContext;  
import javax.servlet.ServletException;  
import javax.servlet.ServletOutputStream;  
import javax.servlet.ServletRequest;  
import javax.servlet.ServletResponse;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  

public class GzipFilter implements Filter {  

    private ServletContext ctx;  
    private Logger logger = Logger.getLogger(GzipFilter.class.getName());  
    private String contextPath;  

    @Override  
    public void destroy() {  

    }  

    @Override  
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
        HttpServletRequest req = (HttpServletRequest) request;  
        HttpServletResponse res = (HttpServletResponse) response;  
        String uri = req.getRequestURI();  
        String accept = req.getHeader("Accept-Encoding");  
        InputStream in = null;  
        contextPath = ctx.getContextPath();  
        uri = uri.substring(contextPath.length());  
        if (accept != null && accept.contains("gzip") && (in = ctx.getResourceAsStream(uri + ".gz")) != null) {  
            logger.info("start getting gzip file "+uri);  
            ByteArrayOutputStream bout = new ByteArrayOutputStream();  
            byte[] b = new byte[1024 * 8];  
            int read = 0;  
            while ((read = in.read(b)) >= 0) {  
                bout.write(b, 0, read);  
            }  
            in.close();  

            res.setHeader("Content-Encoding", "gzip");  
            res.setContentType("application/javascript;charset=UTF-8");  
            res.setContentLength(bout.size());  

            ServletOutputStream out = res.getOutputStream();  
            out.write(bout.toByteArray());  
            out.flush();  
            logger.info("finish getting gzip file "+uri);  
            return;  
        } else {     
            chain.doFilter(request, response);  
        }  
    }  

    @Override  
    public void init(FilterConfig config) throws ServletException {  
        ctx = config.getServletContext();  
    }  

}

配置web.xml

<!-- read the precompressed gzip js file-->  
<filter>  
    <filter-name>gzip</filter-name>  
    <filter-class>GzipFilter</filter-class>  
</filter>  

<filter-mapping>  
    <filter-name>gzip</filter-name>  
    <url-pattern>*.js</url-pattern>  
</filter-mapping>

测试

压缩js文件,比如:a.js 压缩为 a.js.gz 文件

浏览器访问是否成功