一尘不染

使用浏览器后退按钮时重定向副作用

jsp

我们正在使用:

  • JSF 1.2-1.2_07-b03-FCS
  • JSTL 1_1-mr2(特殊构建)
  • Java 1.6.0_22-b04
  • Eclipse 3.6.0(Helios)
  • Tomcat 6.0.28(还需要在Weblogic上运行)
  • IE 7.0.5730.13
  • 的Firefox:6.0

我们有mainForm.jspfilterForm.jspexternalForm.jsp意见。

上有一个按钮“过滤器”,mainForm.jsp可转换为filterForm.jsp。它通过导航规则来做到这一点:

<h:commandButton value="Filter" action="#{mainBean.filterData}" />

mainBean.java代码是:

public String filterData() {
    doStuff();
    return "filter";
}

最初可以正确转换为filterForm.jsp。我们可以mainForm.jsp使用浏览器后退按钮返回。我们可以重复执行此操作。

上面mainForm.jsp有一个表格(实际上是ILog
Gantt图表,但我们认为没有关系),图表栏上带有“弹出”菜单。菜单选项之一是重定向到externalForm.jsp

选择“重定向”会触发以下方法mainBean.java

public void redirect(FacesMenuActionEvent event) {
    if (svr == null) {
        svr = new SetupURL(); // Simple code to set up the full URL
    }

    redirectUrl = svr.redirect(event);  // URL of externalForm.jsp
    svr.redirectData(redirectUrl);
}

这可以正常工作。窗口切换到externalForm.jsp

如果我们按下上的浏览器后退按钮externalForm.jsp,我们将切换回mainForm.jsp,一切看起来都很好。

如果再按“过滤器”按钮,则代码不执行该filterData()方法,而是执行该redirect()方法,然后过渡到externalForm.jsp视图,而不是filterForm.jsp视图。

为什么这样做,我们如何强制呼叫filterData()呢?

******************************************************************************

BalusC - thank you for your solution.  With a few slight tweeks, it worked great.

The changes I made to web.xml are:

    <filter>
       <filter-name>noCacheFilter</filter-name>
       <filter-class>{my package name}.CacheControlFilter</filter-class>
    </filter>
    <filter-mapping>
       <filter-name>noCacheFilter</filter-name>
       <url-pattern>/faces/*</url-pattern>
    </filter-mapping>




Also, I found another solution:

faces-config.xml add:

    <lifecycle>
        <phase-listener id="nocache">{my package name}.
        CacheControlPhaseListener</phase-listener>
    </lifecycle>


Create file CacheControlPhaseListener.java:

package {my package name};

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.addHeader("Pragma", "no-cache");
        response.addHeader("Cache-Control", "no-cache");
        // Stronger according to blog comment below that references HTTP spec
        response.addHeader("Cache-Control", "no-store");
        response.addHeader("Cache-Control", "must-revalidate");
        // some date in the past
        response.addHeader("Expires", "Mon, 8 Aug 2006 10:00:00 GMT");
    }
}

Both seem to work.



Thanks,
John

阅读 332

收藏
2020-06-08

共1个答案

一尘不染

浏览器后退按钮从浏览器缓存中请求结果页面。它不要求服务器重新创建新页面。在您的特定情况下,很可能缓存的页面包含当前无效的JSF视图状态。

最好的解决方法是指示浏览器不要缓存动态JSF页面,而是每次都直接从服务器请求它。您可以在的帮助下执行Filter此操作,该doFilter()方法在方法中包含以下几行:

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

将此映射<servlet-name>FacesServlet中的web.xml。例如

<filter>
   <filter-name>noCacheFilter</filter-name>
   <filter-class>com.example.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
   <filter-name>noCacheFilter</filter-name>
   <servlet-name>facesServlet</servlet-name>
</filter-mapping>
2020-06-08