这段时间一直在使用Page Speed测试页面,一直出现以下几个问题:
根据Google的建议,写了一个Filter来解决这三个问题,代码如下:
/* * GzipAndCacheFilter.java Jan 21, 2010 2:09:31 PM */ package org.shelltea.todo.web.filter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Enumeration; import java.util.zip.GZIPOutputStream; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sf.ehcache.constructs.web.filter.FilterServletOutputStream; import net.sf.ehcache.constructs.web.GenericResponseWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author shelltea * */ public class GzipAndCacheFilter implements Filter { private static final Logger LOG = LoggerFactory .getLogger(GzipAndCacheFilter.class); @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { final HttpServletRequest httpRequest = (HttpServletRequest) request; final HttpServletResponse httpResponse = (HttpServletResponse) response; if (acceptsGzipEncoding(httpRequest)) { if (LOG.isDebugEnabled()) { LOG.debug("gzip:" + httpRequest.getRequestURL()); } // 创建gzip stream final ByteArrayOutputStream compressed = new ByteArrayOutputStream(); final GZIPOutputStream gzout = new GZIPOutputStream(compressed); // 处理request final GenericResponseWrapper wrapper = new GenericResponseWrapper( httpResponse, gzout); chain.doFilter(request, wrapper); wrapper.flush(); gzout.close(); int statusCode = wrapper.getStatus(); if (statusCode != HttpServletResponse.SC_OK) { return; } byte[] compressedBytes = compressed.toByteArray(); httpResponse.setHeader("Content-Encoding", "gzip"); addCacheControl(httpResponse, httpRequest); response.setContentLength(compressedBytes.length); response.getOutputStream().write(compressedBytes); } else { chain.doFilter(request, response); } } @Override public void init(FilterConfig filterConfig) throws ServletException { } private boolean acceptsGzipEncoding(HttpServletRequest request) { return acceptsEncoding(request, "gzip"); } private boolean acceptsEncoding(final HttpServletRequest request, final String name) { final boolean accepts = headerContains(request, "Accept-Encoding", name); return accepts; } private boolean headerContains(final HttpServletRequest request, final String header, final String value) { final Enumeration<?> accepted = request.getHeaders(header); while (accepted.hasMoreElements()) { final String headerValue = (String) accepted.nextElement(); if (headerValue.indexOf(value) != -1) { return true; } } return false; } /** * 根据不同的资源采用不同的缓存策略 * * @param httpResponse * @param httpRequest */ private void addCacheControl(HttpServletResponse httpResponse, HttpServletRequest httpRequest) { String URL = httpRequest.getRequestURL().toString(); if (URL.charAt(URL.length() - 1) == '/') { httpResponse.setHeader("Cache-Control", "private, max-age=0"); httpResponse.setHeader("Expires", "-1"); return; } httpResponse.setHeader("Cache-Control", "public, max-age=31536000"); httpResponse.setHeader("Vary", "Accept-Encoding"); } }
代码中的GenericResponseWrapper和FilterServletOutputStream是引用
在web.xml中加入此过滤器:
<filter> <filter-name>GzipAndCache</filter-name> <filter-class>org.shelltea.todo.web.filter.GzipAndCacheFilter</filter-class> </filter> <filter-mapping> <filter-name>GzipAndCache</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
?以下是使用此过滤器后的Page Speed分析结果:
?
?