Whether concerned about privacy, performance or both, web
site administrators have several means at their disposal to manipulate
client-side caching behavior. In particular, there are two Apache modules,
mod_expires and mod_headers that allow administrators to modify HTTP response
headers in order to control browser caching. Let’s walk through some examples
showing coarse and fine-grain control.
mod_expires Module
This Apache module controls the generation of Expires
headers which tell browsers how long a document should be cached locally based
either on access or modification time.
ExpiresActive Directive
The first step is to make sure that Expires headers will be
generated. To ensure they are, you must activate them as in the following
example:
<IfModule mod_expires.c>
ExpiresActive on
</IfModule>
Alternatively, ExpiresActive off will turn off
Expires header generation.
The ExpiresActive directive can be specified anywhere within
the Apache configuration hierarchy from server level down through virtual host,
directory or .htaccess file. Lower level directives will override higher level
directives so that, for instance, an ExpiresActive directive at the virtual host
level will override the server level directive within that virtual host. Note
that all the mod_expires directives operate within the Apache configuration
hierarchy in this same way, with lower level directives overriding higher level
directives.
Now that Expires headers are enabled, you must specify rules
for generating them. This is done with the ExpiresDefault and ExpiresByType
directives.
Expires Syntax
Documents can be expired based on the amount of time elapsed
from either a) the last time the client accessed the document; or b) the last
time the server modified the document.
There are two different syntaxes available to specify
expiration. The first uses a code (‘A’ or ‘M’) to specify one of the two types
above (access or modification); followed by the number of seconds to add to the
base time to calculate the expiration time. For example:
- A604800
means expire the document 1 week after access; while
- M604800
means expire the document 1 week after it is modified.
It is important to repeat that the “by access” method is
determined at the client side while the “by modification” method is determined
at the server side. Care should be used when specifying the “by modification”
method since all client caches will expire simultaneously and once expired,
will remain expired, and therefore not cached, until the next modification. The
best use case for the “by modification” method is for documents that change on
a regular basis such as a weekly status report or a quarterly financial report.
The “by access” method is far more commonly used.
For the mathematically challenged (“How many seconds are
there in month?”) among us there is an alternative syntax that is somewhat
easier to use. This second syntax is “<base> plus <number> <type>”
and is best explained by example. Transforming the above 1 week examples into
this for format we get either:
- “access
plus 604800 seconds”
- “modification
plus 604800 seconds”
or, more simply
- “access
plus 1 week”
- “modification
plus 1 week”
With the syntax in hand let’s get back to our example where
we’ll use the more user-friendly syntax above.
ExpiresDefault Directive
The ExpiresDefault directive is used to set the default
expiration time for all documents within the realm of the directive unless
otherwise overridden by an ExpiresByType directive.
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault “access plus 4 hours”
</IfModule>
ExpiresByType Directive
Use the ExpiresByType directive to override ExpiresDefault
by type of document thus gaining a finer grain control of caching behavior.
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault “access plus 4
hours”
ExpiresByType image/gif "access
plus 1 month"
ExpiresByType image/jpeg “access
plus 1 month"
ExpiresByType image/tiff
"access plus 1 month"
ExpiresByType image/bmp
"access plus 1 month"
ExpiresByType text/css
"access plus 1 hour"
ExpiresByType
application/x-javascript "access plus 1 hour"
</IfModule>
Here we are expiring images 1 month after they are accessed
and style sheets and javascript 1 hour after access.
mod_headers Module
So far we have activated Expires headers, set default
expiration for all documents and overridden the default expiration for some
document types. The unset, set and append options of the Header directive
within the mod_headers module when used in conjunction with the FilesMatch
directive, allows us to override our ExpiresByType directives to give us the
finest grain cache control possible. Consider the following two use cases.
Let’s assume our working example was specified at the server
level, meaning it applies to all virtual hosts on the server. Let’s further
assume that we have one web site that handles sensitive content that we prefer
not to cache on client machines. Assuming that site has its own virtual host we
can specify the following directives within that site’s virtual host:
<FilesMatch "\.(html?|gif|jpe?g|jsp?|css|do|js|pdf)$">
Header unset Cache-Control
Header append Cache-Control
"private, no-cache, no-store"
Header append Pragma
"no-cache"
</FilesMatch>
These directives unset any previous cache control headers
and append new headers indicating not to cache the selected file types.
Finally, within this same virtual host, there is a
particularly large file that is frequently downloaded and you want to override
the above no-cache directives just for this file. The following directives will
accomplish this:
<FilesMatch "myLargeFile\.pdf">
Header unset Cache-Control
Header unset Pragma
Header append Cache-Control
"public"
</FilesMatch>