How can I get static content on Apache to be {cached by browser} and not {checked for freshness {with every request}}?
I'm working on a website hosted on Apache webserver. Recently, I was testing something with headers (Content-Type for different types of content) and saw a lot of conditional requests for images. Example:
200 /index.php?page=1234&action=list
304 /favicon.ico
304 /img/logo.png
304 /img/arrow.png
(etc.)
Although the image files are static content and are cached by the browser, every time an user opens a page that links to them, they are conditionally requested, to which they send "304 Not Modified". That's good (less data transferred), but it means 20+ more requests with every page load (longer page load due to all those round-trips, even with Keep-Alive and pipelining enabled).
How do I tell the browser to keep the existing file and not check for newer version?
EDIT: the mod_expires method works, even with the favicon.
The Apache HTTP server offers a low level shared object cache for caching information such as SSL sessions, or authentication credentials, within the socache interface. Additional modules are provided for each implementation, offering the following backends: mod_socache_dbm. DBM based shared object cache.
Image caching essentially means downloading an image to the local storage in the app's cache directory (or any other directory that is accessible to the app) and loading it from local storage next time the image loads.
Expires module in Apache solves this
a2enmod expires
it needs to be loaded in server config, and set up in .htaccess
(or in server config).
With an Expires header, the resource is only requested the first time. Before the expiration date, subsequent requests are fulfilled from browser cache. After the specified time expires and the resource is needed, only then it is requested again (conditionally - a 304 will be returned for an unchanged resource). The only reliable way to clear it from the cache before it expires is manually, or by forcing a refresh (usually Ctrl-F5). (This could be an issue if the resource changes in the meantime, but statical images don't change very often.)
# enable the directives - assuming they're not enabled globally
ExpiresActive on
# send an Expires: header for each of these mimetypes (as defined by server)
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
# css may change a bit sometimes, so define shorter expiration
ExpiresByType text/css "access plus 1 days"
For favicon.ico, a bit more work is needed (Apache normally does not recognize Windows icon files, and sends this as the default text/plain).
# special MIME type for icons - see http://www.iana.org/assignments/media-types/image/vnd.microsoft.icon
AddType image/vnd.microsoft.icon .ico
# now we have icon MIME type, we can use it
# my favicon doesn't change much
ExpiresByType image/vnd.microsoft.icon "access plus 3 months"
And voila, It Works™!
With the filesMatch
directive, instead of ExpiresByType
, you can group Content-Type
by matching subtype
(e.g. image/*
), instead of listing each type/subtype
pair, not subtype
(e.g image/jpeg
, image/png
).
#Set caching on image files for 11 months
<filesMatch "\.(ico|gif|jpg|png)$">
ExpiresActive On
ExpiresDefault "access plus 11 month"
Header append Cache-Control "public"
</filesMatch>
Acoording to this Google article I made expiration not longer than 1 year (access plus 11 month
) and added Cache-Control "public"
to enable HTTPS caching for Firefox.
For CSS and JS, Google recommends an expiry period of 1 week.
<filesMatch "\.(css|js)$">
ExpiresActive On
ExpiresDefault "access plus 1 week"
Header append Cache-Control "public"
</filesMatch>
If you set the Expires
header on your http response for your static images, your server won't be checked again for that image after first download until the time specified has passed, e.g. if I download a file from your server now that gives it's Expires
header as
Expires: Fri, 1 Jan 2010 00:00:01 GMT
then my browser won't look for it from your server again until 2010, unless I clear my cache/do a force refresh (Ctrl+F5 on windows).
There's a simple introduction to setting this up here, and a list of other possibly helpful responses over at wikipedia
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With