【问题标题】:JSF Cache Static Resources FilterJSF 缓存静态资源过滤器
【发布时间】:2013-02-10 01:31:01
【问题描述】:

如何编写一个过滤器,以按照 Google (https://developers.google.com/speed/docs/best-practices/caching) 的建议适当缓存静态资源。

创建一个将上次修改日期设置为某个静态日期的过滤器是否足够(每次服务器重新启动时都会更改)?

指定 Expires 或 Cache-Control max-age 之一很重要, 和 Last-Modified 或 ETag 之一,用于所有可缓存资源。它是 多余地指定 Expires 和 Cache-Control: max-age,或 同时指定 Last-Modified 和 ETag。

上面的链接似乎建议您需要指定 Expires 或 Cache-Control。为什么有必要?

【问题讨论】:

    标签: jsf servlet-filters browser-cache


    【解决方案1】:

    如何编写一个过滤器,以按照 Google 的建议适当缓存静态资源

    如果您的意思是使用 JSF 资源 /resources 文件夹中的文件,这些文件完全由 JSF 内置资源处理程序 (and thus all referenced via <h:outputStylesheet>, <h:outputScript>, <h:graphicImage>, #{resource} and thus not via the plain HTML way) 处理,那么您不需要为该作业自行开发过滤器。要满足 Google 的建议,您唯一需要做的就是将Expires 日期设置得更远一点。即默认为 7 天(604800000 毫秒),而 Google Page Speed 和 Yahoo YSlow 等性能测试工具建议至少 30 天(2592000000 毫秒)。

    在 Mojarra 中,您可以使用 web.xml 中的以下上下文参数进行设置:

    <context-param>
        <param-name>com.sun.faces.defaultResourceMaxAge</param-name>
        <param-value>2592000000</param-value> <!-- 30 days -->  
    </context-param>
    

    在 MyFaces 中使用以下一个:

    <context-param>
        <param-name>org.apache.myfaces.RESOURCE_MAX_TIME_EXPIRES</param-name>
        <param-value>2592000000</param-value> <!-- 30 days -->  
    </context-param>
    

    创建一个将最后修改日期设置为某个静态日期的过滤器是否足够(每次服务器重新启动时都会更改)?

    您不需要也不应该设置Last-Modified。 JSF 资源处理程序已经自动执行此操作。如果您因为更改了资源而想强制重新加载资源,请使用资源库版本控制。另见What is the JSF resource library for and how should it be used?

    请注意,每次服务器重新启动时更改它是没有意义的,因为 Expires 标头仍会一直告诉浏览器仅在一段时间后重新测试缓存的有效性。在浏览器真正请求资源之前,浏览器永远不会注意到资源的Last-Modified 的变化。唯一迫使浏览器难以完全重新请求资源的是 URL 的更改,通常通过更改查询字符串参数值来实现。 JSF 资源库版本控制正是这样做的。

    另请注意,OmniFaces CombinedResourceHandler 使用资源的最后修改时间戳作为查询字符串中的“资源版本”,而不是资源库版本。因此,如果您使用它,则不一定需要资源库版本控制机制。


    上面的链接似乎建议您需要指定 Expires 或 Cache-Control。为什么有必要这样做?

    Expires 标头告诉浏览器何时通过条件 GET 请求重新测试缓存资源的有效性。因此,在此之前,浏览器不会这样做,并将继续使用缓存中的那个。 Cache-Control 告诉浏览器使用哪种缓存策略。请注意,当它设置为例如no-cache 而不是 public,那么 Expires 标头将无效。另请注意,缺少 Cache-Control 标头意味着 public(由 JSF 资源完成)。

    【讨论】:

    • 记住 defaultResourceMaxAge 仅在 javax.faces.PROJECT_STAGE 设置为 Production 时才有效
    【解决方案2】:

    这是我编写缓存过滤器的方式。像魅力一样工作。

    编写缓存过滤器以提高 JSF/Servlet 屏幕静态内容的性能

    在您的 web.xml 中添加以下内容

    <filter>
        <filter-name>cache</filter-name>
        <filter-class>au.com.webapp.config.CacheFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>cache</filter-name>
        <url-pattern>*.xhtml</url-pattern>
    </filter-mapping>
    

    在您的 au.com.webapp.config 包中创建一个类 CacheFilter,如下所示:

    package au.com.webapp.config;
    
    import java.io.IOException;
    
    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;
    
    public class CacheFilter implements Filter {
        private static long maxAge = 86400 * 30; // 30 days in seconds
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            String uri = ((HttpServletRequest) request).getRequestURI();
            if (uri.contains(".js") || uri.contains(".css") || uri.contains(".svg") || uri.contains(".gif")
                    || uri.contains(".woff") || uri.contains(".png")) {
                httpResponse.setHeader("Cache-Control", "max-age=" + maxAge);
            }
            chain.doFilter(request, response);
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("Cache Filter started: ");
    
        }
    
        @Override
        public void destroy() {
        }
    }
    

    如何验证我的屏幕是否正在使用缓存

    要查看您的内容是否已经使用 gzip 和缓存,请在您的 Google Chrome 浏览器中 -> 右键单击​​屏幕 -> 检查 -> 单击网络选项卡 -> 刷新屏幕。 点击图片、图标、样式表,看看您是否在响应标题

    中看到以下内容

    Cache-Control:max-age=2592000

    同样当你刷新页面时,如果元素的状态是 304 而不是 200(来自缓存),你就完成了。

    gzip 等其他性能改进

    请参阅以下链接,了解可以显着改变您的 web 应用或网站性能的其他简单性能改进,例如 gzip 或 JQuery UI 组件。 https://*.com/a/35567464/5076414

    【讨论】:

      【解决方案3】:

      无需编写过滤器,Tomcat 7 已经有 ExpiryFilter 可以将 Cache-Control 添加到您的资源中。它可以基于修改或访问时间。请参阅此博客:

      http://kahimyang.info/kauswagan/howto_blogs/1574-improving_page_load_with_mod_expires_and_expiresfilter_in_jsf_applications

      【讨论】: