Book: JavaServer Pages™, 2nd Edition
Section: Chapter 16.  Bits and Pieces



16.5 Preventing Caching of JSP Pages

A browser can cache web pages so that it doesn't have to get them from the server every time the user asks for them. Proxy servers can also cache pages that are frequently requested by all users going through the proxy. Caching helps cut down the network traffic and server load, and provides the user with faster responses. But caching can also cause problems in a web application in which you really want the user to see the latest version of a dynamically generated page.

Both browsers and proxy servers can be told not to cache a page by setting response headers. You can use a scriptlet like this in your JSP pages to set these headers:

<%
  response.addHeader("Pragma", "no-cache");
  response.setHeader("Cache-Control", "no-cache");
  response.setDateHeader("Expires", 0);
%>

An alternative is to use a custom action that's included with the book examples:

<%@ taglib uri="orataglib" prefix="ora" %>
<ora:noCache/>

The <ora:noCache> action sets the exact same headers as the scriptlet example, but it's cleaner.

The Pragma header is intended for old HTTP/1.0 clients. According to the HTTP/1.0 specification, this header is really a request header but proxies and some browsers are known to respect it even when it's used as a response header. The Cache-Control header is an HTTP/1.1 header, so older browsers may not recognize it. The no-cache value means that the client is not allowed to save a local copy of the page. The Expires header is defined by the HTTP/1.0 specification, so all browsers should recognize it. The value is the date and time when the response is no longer valid. The setDateHeader( ) method converts the value 0 to Thu, 1 Dec 1970 00:00:00 GMT; in other words, a date way in the past to ensure that the client gets a new copy every time this page is requested.

There's a subtle difference between telling the browser that the response has already expired and telling it not to cache the response. According to the HTTP/1.1 specification, if you say only that the response has expired, the browser is supposed to show a cached copy when the user uses the Back button or selects the page from the history list. It should ask the server for a new version only when the user makes an explicit request for the page by clicking a link, submitting a form, or typing the URL in the address field. However, if you tell the browser not to cache the response, it's not allowed to ever use a cached copy, not even for a Back button or history list selection. This is the safest model for responses that include sensitive information intended only for an authorized user, but it may not be the right choice for all responses.

By including or excluding the Pragma and Cache-Control headers, you can get the behavior that is appropriate for your specific application. In theory, that is. Unfortunately, browsers don't always behave as they should. Most (if not all) versions of Netscape and Mozilla, for instance, don't cache a response that has expired so excluding the cache headers makes no difference. Some versions of Internet Explorer are infamous for ignoring the cache headers, forcing you to use <http-equiv> elements in the page instead of (or in addition to) setting the headers to avoid a response to be cached. For more on the Internet Explorer problems, see http://support.microsoft.com/default.aspx?scid=kb;EN-US;q222064. Finally, some proxy and caching servers ignore all of this. An ugly but effective workaround in this case is to generate unique URLs for all application pages by including a query string parameter with a new value for each request, for instance using a counter like this:

<c:set var="${counter + 1}" scope="application" />
<a href="mypage.jsp?nocache=<c:out value="${counter} />">
  This page is never cached</a>

As you can see, in the real world it can be hard to get this right. I recommend that you set the appropriate headers for the behavior you want first, assuming that the browsers and proxies used by the web application users are specification-compliant. Then test with the set of browser versions you want to support, using all the caching options each browser supports. Revert to <http-equiv> elements or the unique query string solution only if nothing else works.

    [http://safari.oreilly.com/059600317X/jserverpages2-CHP-16-SECT-5]


    Copyright © 2002 O'Reilly & Associates, Inc. All rights reserved.
    1005 Gravenstein Highway North
    Sebastopol, CA 95472