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.
|