public class CacheControlFilter extends HttpFilter
This filter will control the cache-related headers of the response. Cache-related headers have a major impact on performance (network bandwidth and server load) and user experience (up to date content and non-expired views).
By default, when no initialization parameters are specified, the filter will instruct the client (generally, the
webbrowser) to not cache the response. This is recommended on dynamic pages with stateful forms with
a javax.faces.ViewState
hidden field. If such a page were cached, and the enduser navigates to it by
webbrowser's back button, and then re-submits it, then the enduser would face a
ViewExpiredException
.
However, on stateless resources, caching the response would be beneficial. Set the expire time to the same time as you'd like to use as refresh interval of the resource, which can be 10 seconds (to avoid F5-madness on resources which are subject to quick changes), but also minutes or even hours, days or weeks. For example, a list of links, a news page, a JS/CSS/image file, etc.
Any sane server and client adheres the following rules as to caching:
ETag
or Last-Modified
header is present on cached resource, then the client
will perform a so-called conditional GET request with If-None-Match
or If-Modified-Since
headers. If the server responds with HTTP status 304 ("not modified") along with the updated cache-related headers,
then the client will keep the resource in cache and expand its expire time based on the headers. Note:
ETag
takes precedence over Last-Modified
when both are present and consequently
If-None-Match
takes precedence over If-Modified-Since
when both are present.
Ctrl
key
along with refresh button or F5, then the webbrowser will perform a fresh new request and purge any cached resource.
Important notice: this filter automatically skips JSF resources, such as the ones served by
<h:outputScript>
, <h:outputStylesheet>
, @ResourceDependency
, etc.
Their cache-related headers are namely already controlled
by the ResourceHandler
implementation. In Mojarra and MyFaces, the default expiration time is 1 week
(604800000 milliseconds), which can be configured by a web.xml
context parameter with the following name and
a value in milliseconds, e.g. 3628800000
for 6 weeks:
com.sun.faces.defaultResourceMaxAge
org.apache.myfaces.RESOURCE_MAX_TIME_EXPIRES
It would not make sense to control their cache-related headers with this filter as they would be overridden anyway.
This filter supports the expires
initialization parameter which must be a number between 0 and 999999999
with optionally the 'w', 'd', 'h', 'm' or 's' suffix standing for respectively 'week', 'day', 'hour', 'minute' and
'second'. For example: '6w' is 6 weeks. The default suffix is 's'. So, when the suffix is omitted, it's treated as
seconds. For example: '86400' is 86400 seconds, which is effectively equal to '86400s', '1440m', '24h' and '1d'.
Imagine that you've the following resources:
/forum/*
pages: cache 10 seconds.
*.pdf
and *.zip
files: cache 2 days.
Then you can configure the filter as follows (filter name is fully free to your choice, but keep it sensible):
<filter> <filter-name>noCache</filter-name> <filter-class>org.omnifaces.filter.CacheControlFilter</filter-class> </filter> <filter> <filter-name>cache10seconds</filter-name> <filter-class>org.omnifaces.filter.CacheControlFilter</filter-class> <init-param> <param-name>expires</param-name> <param-value>10s</param-value> </init-param> </filter> <filter> <filter-name>cache2days</filter-name> <filter-class>org.omnifaces.filter.CacheControlFilter</filter-class> <init-param> <param-name>expires</param-name> <param-value>2d</param-value> </init-param> </filter> <filter-mapping> <filter-name>noCache</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>cache10seconds</filter-name> <url-pattern>/forum/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>cache2days</filter-name> <url-pattern>*.pdf</url-pattern> <url-pattern>*.zip</url-pattern> </filter-mapping>
Note: put the more specific URL patterns in the end of filter mappings. Due to the way how filters work, there's
unfortunately no simple way to skip the filter on /*
when e.g. *.pdf
is matched. You can
always map the no cache filter specifically to FacesServlet
if you intend to disable caching on
all JSF pages. Here's an example assuming that you've configured the FacesServlet
with
a servlet name of facesServlet
:
<filter-mapping> <filter-name>noCache</filter-name> <servlet-name>facesServlet</servlet-name> </filter-mapping>
If the expires
init param is set with a value which represents a time larger than 0 seconds, then the
following headers will be set:
Cache-Control: public,max-age=[expiration time in seconds],must-revalidate
Expires: [expiration date of now plus expiration time in seconds]
If the expires
init param is absent, or set with a value which represents a time equal to 0 seconds,
then the following headers will be set:
Cache-Control: no-cache,no-store,must-revalidate
Expires: [expiration date of 0]
Pragma: no-cache
To speed up development, caching by this filter is disabled when JSF project stage is set to
Development
as per Servlets.isFacesDevelopment(javax.servlet.ServletContext)
.
Constructor and Description |
---|
CacheControlFilter() |
Modifier and Type | Method and Description |
---|---|
void |
doFilter(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
FilterChain chain)
Set the necessary response headers based on
expires initialization parameter. |
void |
init()
Initialize the
expires parameter. |
static void |
setCacheHeaders(HttpServletResponse response,
long expires)
Set the cache headers.
|
static void |
setNoCacheHeaders(HttpServletResponse response)
Set the no-cache headers.
|
destroy, doFilter, getFilterConfig, getInitParameter, getServletContext, init
public void init() throws ServletException
expires
parameter.init
in class HttpFilter
ServletException
- When filter's initialization failed.public void doFilter(HttpServletRequest request, HttpServletResponse response, HttpSession session, FilterChain chain) throws ServletException, IOException
expires
initialization parameter.doFilter
in class HttpFilter
request
- The HTTP request.response
- The HTTP response.session
- The HTTP session, if any, else null
.chain
- The filter chain to continue.ServletException
- As wrapper exception when something fails in the request processing.IOException
- Whenever something fails at I/O level.Filter.doFilter(ServletRequest, ServletResponse, FilterChain)
public static void setCacheHeaders(HttpServletResponse response, long expires)
Set the cache headers. If the expires
argument is larger than 0 seconds, then the following headers
will be set:
Cache-Control: public,max-age=[expiration time in seconds],must-revalidate
Expires: [expiration date of now plus expiration time in seconds]
Else the method will delegate to setNoCacheHeaders(HttpServletResponse)
.
response
- The HTTP servlet response to set the headers on.expires
- The expire time in seconds (not milliseconds!).public static void setNoCacheHeaders(HttpServletResponse response)
Set the no-cache headers. The following headers will be set:
Cache-Control: no-cache,no-store,must-revalidate
Expires: [expiration date of 0]
Pragma: no-cache
response
- The HTTP servlet response to set the headers on.Copyright © 2012–2015 OmniFaces. All rights reserved.