为组件添加Expires头,最大化利用浏览器缓存

来源:互联网 发布:猪八戒软件 编辑:程序博客网 时间:2024/05/18 00:07

web项目一旦部署完毕,项目中的图片、CSS以及JS基本上很少发生变动,那么假如把这些组件缓存在浏览器客户端,而不再从服务器上获取,那么网站的访问者在首次访问网站后,后续的请求将会大量减轻服务器的请求压力。这一举动,带来的性能提升,可以称作完美!那么如何做呢?那就是为组件添加Expires(期限)头!

一、了解Expires头

起初,在读《高性能web建站指南》第三章“添加Expires头”时,感觉很有压力,因为不了解Expires头是做什么用的,所以就没有心思去实践该做法,就搁置了一段时间。然而今天心情很好,耐着性子在网上找一系列的资源,并且重读这篇文章,实践再三,终于搞定,特此分享,希望更多的朋友能够看到,实践到你的项目中,从而提升网站性能。

我提供几篇文章大家读一读:

  1. tomcat7官方doc中给出的Expires_Filter,可结合源码进行分析。
  2. 浏览器缓存详细解析
  3. HTTP1.1 协议
  4. 网站性能优化:cache-control设置详解

有了这几篇文章作为铺垫,我想你基本上就可以了解Expires头啦。

二、效果

这里写图片描述

对于一个添加了Expires头的css来说,其请求的信息如图,多了max-age,以及Expires,这两者之间的关系我也不再赘述,之前的文章中描述比较清楚。

三、实现方法

①、新建CacheControlFilter.java

package com.honzh.common.filter;import java.io.IOException;import java.util.Calendar;import java.util.Date;import java.util.Enumeration;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 org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;public class CacheControlFilter implements Filter {    private FilterConfig config = null;    private static final String CACHE_CONTROL_BY_TYPE = "Cache-Control";    private static final String HEADER_EXPIRES = "Expires";    private static final Log log = LogFactory.getLog(CacheControlFilter.class);    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,            ServletException {        if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {            HttpServletResponse httpResponse = (HttpServletResponse) response;             HttpServletRequest httpRequest = (HttpServletRequest) request;            boolean cacheControlSet = false;            for (Enumeration<String> names = config.getInitParameterNames(); names.hasMoreElements();) {                String headerName = (String) names.nextElement();                log.debug("参数名称:" + headerName);                String value = config.getInitParameter(headerName);                log.debug("参数值:" + value);                // 说明包含了类型,此时要筛选符合条件的类型                String type = headerName.substring(CACHE_CONTROL_BY_TYPE.length()).trim();                log.debug("参数规定的类型:" + type);                String contentType = httpRequest.getHeader("Accept");                log.debug("请求内容类型为:" + contentType);                if (contains(contentType, ";")) {                    // lookup content-type without charset match (e.g.                    // "text/html")                    String contentTypeWithoutCharset = substringBefore(contentType, ";").trim();                    if (contentTypeWithoutCharset.indexOf(type) != -1) {                        // 类型匹配,再看值是不是max-age,如果是,将max-age设置为当前时间+1个月                        Calendar calendar = Calendar.getInstance();                        calendar.setTime(new Date());                        calendar.add(Calendar.MONTH, 1);                        Date expirationDate = calendar.getTime();                        httpResponse.setDateHeader(HEADER_EXPIRES, expirationDate.getTime());                        String maxAgeDirective = "max-age="                                + ((expirationDate.getTime() - System.currentTimeMillis()) / 1000);                        setControlHeader(httpResponse, "private," + maxAgeDirective);                        cacheControlSet = true;                    }                }            }            if (!cacheControlSet) {                setControlHeader(httpResponse, "private");            }        }        chain.doFilter(request, response);        // resp.setHeader("Expires", "Tue, 03 Jul 2001 06:00:00 GMT");        // resp.setDateHeader("Last-Modified", new Date().getTime());        // resp.setHeader("Cache-Control",        // "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");        // resp.setHeader("Cache-Control", "private");        // resp.setHeader("Pragma", "no-cache");    }    private void setControlHeader(HttpServletResponse httpResponse, String cache_control) {        String cacheControlHeader = httpResponse.getHeader(CACHE_CONTROL_BY_TYPE);        String newCacheControlHeader = (cacheControlHeader == null) ? cache_control : cacheControlHeader + ", "                + cache_control;        httpResponse.setHeader(CACHE_CONTROL_BY_TYPE, newCacheControlHeader);    }    @Override    public void destroy() {    }    @Override    public void init(FilterConfig config) throws ServletException {        this.config = config;    }    protected static boolean contains(String str, String searchStr) {        if (str == null || searchStr == null) {            return false;        }        return str.indexOf(searchStr) >= 0;    }    protected static String substringBefore(String str, String separator) {        if (str == null || str.isEmpty() || separator == null) {            return null;        }        if (separator.isEmpty()) {            return "";        }        int separatorIndex = str.indexOf(separator);        if (separatorIndex == -1) {            return str;        }        return str.substring(0, separatorIndex);    }}
  1. web.xml中我们为Expires设置了三种类型,分别为image、css、js,②中有详细参数,这样在filter中,我们将为这三种类型添加Expires、max-age。
  2. 至于类中提到的private,你可以关注我的另一篇文章gzip压缩tomcat服务器响应包,大幅提升web性能。
  3. 其他方面,代码不复杂,主要的是做法,我将做法提供给大家。

②、web.xml

<filter>        <filter-name>cacheControlFilter</filter-name>        <filter-class>com.honzh.common.filter.CacheControlFilter</filter-class>        <init-param>            <param-name>Cache-Control image</param-name>            <param-value>max-age</param-value>        </init-param>        <init-param>            <param-name>Cache-Control text/css</param-name>            <param-value>max-age</param-value>        </init-param>        <init-param>            <param-name>Cache-Control application/javascript</param-name>            <param-value>max-age</param-value>        </init-param>    </filter>    <filter-mapping>        <filter-name>cacheControlFilter</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>

以上,两个步骤(为组件添加Expires头)完成后,你的项目就又在性能上有了进一步的提升,感觉怎么样呢?

3 0
原创粉丝点击