12

I am using following meta tags to prevent browser caching for page:

<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="-1" />
<meta http-equiv="Vary" content="*" />

Case:

  1. Browser is already opened with page1.
  2. New link is pasted in the browser address bar and now secured page page2 is opened.
  3. User performs action on page2 and is redirected to page3.

When clicking back button on page3, then user gets redirected to page1 (no caching and works fine in this case). When user clicks forward button on page1, then the user is forwarded to the secured page page2. This shouldn't happen.

All of above is tested on IE9.

How is this caused and how can I solve it?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Mahmoud Saleh
  • 33,303
  • 119
  • 337
  • 498
  • 5
    Can the down voters please correct me if i am wrong in something and not just down vote ? – Mahmoud Saleh Nov 03 '13 at 10:56
  • 2
    always use a web filter to prevent browser to cache your pages see this for the code of web filter http://stackoverflow.com/questions/19018130/redirect-to-login-page-when-user-clicks-on-back-button-after-logout-in-jsf/19034603#19034603 – hanan Ahmed Nov 03 '13 at 11:54
  • 5
    + upvote for unjustified downvote – fareed Nov 03 '13 at 11:56
  • @hanan Ahmed, what exactly this filter does ? – Mahmoud Saleh Nov 03 '13 at 12:20
  • A quick note: it seems not necessary to use both `post-check=0, pre-check=0`. It might even cause unexpected behavior on some browsers! See more information here: http://blogs.msdn.com/b/ieinternals/archive/2009/07/20/using-post_2d00_check-and-pre_2d00_check-cache-directives.aspx – JustAMartin Jun 13 '14 at 14:09

2 Answers2

7

Your initial attempt with HTML <meta http-equiv> tags specifies the right header values, however, this doesn't work at all because your pages are already served over HTTP. The <meta http-equiv> headers specifies "HTTP-equivalent" headers which are only used when the pages are not served using the HTTP protocol.

For example, when the pages are opened from local disk file system like as if you were doubleclicking a .html file in local disk file system explorer. This would open the .html file via file:// URI instead of http:// URI.

You should be setting those headers on the real HTTP response. You can investigate the headers of the current HTTP response by pressing F12 in Chrome/FireFox>=23/IE>=9 and exploring the HTTP traffic in Network tab. In case of specifically IE9/10, click the Start capturing button, reload the page, select the HTML page, click Go to detailed view button and finally click the Response headers tab. Here's a screenshot of how it look like in IE10 on your current question:

enter image description here

The right way to get those headers to end up there is using HttpServletResponse#setHeader() and friends like setDateHeader(), addHeader(), etc. As you figured, one way is a servlet filter.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
1

I found out that the best solution is the following filter:

import java.io.IOException;
import javax.faces.application.ResourceHandler;
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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet Filter implementation class NoCacheFilter
 */
  @WebFilter(urlPatterns = {"*.xhtml"})
  public class NoCacheFilter implements Filter {

/**
 * Default constructor. 
 */
public NoCacheFilter() {
    // TODO Auto-generated constructor stub
}

/**
 * @see Filter#destroy()
 */
public void destroy() {
    // TODO Auto-generated method stub
}

/**
 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
 */

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;

    // apply no caching for all web pages except resources, you can customize that to be applied for specific pages
    if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
        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);
}
/**
 * @see Filter#init(FilterConfig)
 */
public void init(FilterConfig fConfig) throws ServletException {
    // TODO Auto-generated method stub
}

}

according to the answer in this question:

Redirect to login page when user clicks on back button after logout in JSF

Community
  • 1
  • 1
Mahmoud Saleh
  • 33,303
  • 119
  • 337
  • 498