如何在JSF2中禁用静态资产缓存,如.css和.js文件?

5

我正在尝试设置一个项目,以便不缓存静态资源。.css和.js。我们似乎有一些内部缓存问题,我希望这能解决问题。

我已经安装了一个阶段监听器,基本上是这个http://turbomanage.wordpress.com/2006/08/08/disable-browser-caching-in-jsf/的稍微修改版本。

我的类:

package com.ods.common.jsf.phaselistener;

import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpServletResponse;

public class CacheControlPhaseListener implements PhaseListener
{
public PhaseId getPhaseId()
{
    return PhaseId.RENDER_RESPONSE;
}

public void afterPhase(PhaseEvent event)
{
}

public void beforePhase(PhaseEvent event)
{
    FacesContext facesContext = event.getFacesContext();
    HttpServletResponse response = (HttpServletResponse) facesContext
            .getExternalContext().getResponse();
    response.setHeader("Cache-control", "no-cache"); // HTTP 1.1
    response.setHeader("Cache-control", "no-store"); // HTTP 1.1
    response.setHeader("Cache-control", "must-revalidate"); // HTTP 1.1
    // response.setHeader("Pragma","no-cache"); //HTTP 1.0
    response.setHeader("Allow", "GET"); // Allowing GET Method only
    response.setHeader("Allow", "POST");// Allowing POST Method only
    response.setDateHeader("Expires", -1); // prevent caching at the proxy server

            /*what I've added*/
    response.setHeader("Pragma", "no-cache");
    response.setHeader("Content-type", "x-javascript");
            //below are the content types I'm seeing for the css/js assets via Firebug
    response.setHeader("Content-type", "application/x-javascript");
    response.setHeader("Content-type", "text/css");
}
}

我对faces-config.xml的添加:

<lifecycle>
    <phase-listener id="nocache">com.ods.common.jsf.phaselistener.CacheControlPhaseListener</phase-listener>
</lifecycle>

我的.xhtml页面在过去得到了一个过期的头部:
Expires Thu, 01 Jan 1970 00:00:00 GMT

所以这似乎有些起作用...我假设这个日期是来自Expires -1(将其设置为Unix纪元)。

正如您所看到的,我尝试为一些JavaScript和CSS设置适当的内容类型标头,但这些资产的到期日期是未来一周。

有人有什么想法吗?另外,我是前端开发人员,不是后端Java人员。我可以玩Java,但我绝对不是Java开发人员。这也是我第一次使用JSF,因此尽可能简单易懂会很好 :)

1个回答

15
使用setHeader()会覆盖先前设置的任何标头。相反,应该使用addHeader(),或者将所有值用逗号分隔作为标头值。以下是完整的设置:
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.

你的另一个错误是认为 PhaseListener 是最好的地方。它仅在 JSF 页面请求时被调用,而不是由 Web 浏览器独立调用的静态资源请求。换句话说,只有 JSF 页面本身禁用了缓存,但所有的 <script><link><img> 等都会生成新的请求,这些请求不会调用那个 PhaseListener,因为它们不是 JSF 页面。
相反,请使用 Filter
@WebFilter("/*")
public class NoCacheFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
        response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
        response.setDateHeader("Expires", 0); // Proxies.
        chain.doFilter(req, res);
    }

    // ... (just keep init() and destroy() NO-OP)
}

如果您的目标是Servlet 3.0容器(Tomcat 7、Glassfish 3等),则不需要进行web.xml(或faces-config.xml)注册。 @WebFilter("/*")将自动注册并将其映射到一个/* URL模式,从而覆盖所有请求。

另请参阅:


与具体问题无关,完全禁用静态资产缓存并不是最好的选择。这会不必要地消耗网络带宽。相反,应寻找其他解决方案,例如在查询字符串中包含服务器启动时间戳。

例如:

<script src="foo.js?#{startup.time}"></script>

faces-config.xml 中。
<managed-bean>
    <managed-bean-name>startup</managed-bean-name>
    <managed-bean-class>java.util.Date</managed-bean-class>
    <managed-bean-scope>application</managed-bean-scope>
</managed-bean>

这个例子会在服务器重新启动时强制浏览器重新加载资源。

如果我只想要 .css 和 .js 文件,我需要两个单独的过滤器吗?@WebFilter("/path/to/css") 和 @WebFilter("/path/to/javascript")。 - magenta placenta
2
使用 @WebFilter(urlPatterns={"*.js","*.css"}) - BalusC
1
注意:对于Servlet 2.5,你当然需要老式的web.xml注册。有关具体示例,请参见http://stackoverflow.com/tags/servlet-filters/info。 - BalusC
设置资源的头并自定义其处理,实际上是 javax.faces.application.Resource 的工作。我建议注册一个覆盖自定义 Resource 处理的 ResourceHandler。另请参见自定义 ResourceHandlerMojarra 实现 - YoYo
@YoYo:并非所有静态资源都会通过 FacesServlet - BalusC
在真正的生产环境中,它可能根本不会由Servlet容器处理。 - YoYo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接