apachedude
18 Jan 2007, 01:43 AM
HTTP 1.1 contains powerful cache-control mechanisms to allow clients to place requirements on the operations of network caches. The specific method will be discussed below. (this post is specific to Apache, external links talk about using ASP, IIS, PHP, perl, CGI, Coldfusion, etc.)
Browsers automatically cache files, but they do so in a "must-revalidate" way. That means that they cache the files on your server, but every single time you use that cache by going back to the cached page, your browser send a 301 If-Modified header to check and see if you have modified the cached file since that time. Basically most images, css, javascript, and other files can be optimized for faster loading by telling your visitors browsers to cache them for a certain period of time. The default behaviour is to check the last-modified and/or the Etag headers of the file EVERY time it is requested.
By employing the methods in this article you can totally eliminate these unneccessary 301s and dramatically speed up the loading and rendering of your site. When you implement the caching method described in this article, you can specify that certain files or filetypes be cached for a specific amount of time. These files are then cached by your site visitors and they do not send the If-Modified-Since until the set cache time has completed.
The first solution uses the Apache Module mod_expires 1.3 (http://www.askapache.com/docs/1.3/mod/mod_expires.html)|2.0 (http://www.askapache.com/docs/2.0/mod/mod_expires.html)|2.2 (http://www.askapache.com/docs/2.2/mod/mod_expires.html)
ExpiresActive On
#every filetype not listed below gets cached 300
ExpiresDefault A300
# YEAR
ExpiresByType image/x-icon A29030400
# MONTH
ExpiresByType video/x-flv A2419200
ExpiresByType application/pdf A2419200
# WEEK
ExpiresByType image/gif A604800
ExpiresByType image/png A604800
ExpiresByType image/jpeg A604800
ExpiresByType application/x-shockwave-flash A604800
#hour
ExpiresByType application/x-javascript A3600
ExpiresByType application/xml A3600
ExpiresByType text/css A3600
ExpiresByType text/plain A3600
#5 minutes
ExpiresByType text/html A300
The second solution uses mod_headers 1.3 (http://www.askapache.com/docs/1.3/mod/mod_headers.html)|2.0 (http://www.askapache.com/docs/2.0/mod/mod_headers.html)|2.2 (http://www.askapache.com/docs/2.2/mod/mod_headers.html)
Example 1
# YEAR
<FilesMatch "\.(ico)$">
Header set Cache-Control "max-age=29030400, public"
</FilesMatch>
# MONTH
<FilesMatch "\.(flv|pdf)$">
Header set Cache-Control "max-age=2419200, public"
</FilesMatch>
# WEEK
<FilesMatch "\.(swf|css)$">
Header set Cache-Control "max-age=604800, private, must-revalidate"
</FilesMatch>
# NEVER CACHE
<FilesMatch "\.(html|cgi|php|htm)$">
Header set Expires "Fri, 04 Aug 1978 12:00:00 GMT"
Header set Cache-Control "no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, no-transform"
Header set Pragma "no-cache"
</FilesMatch>
Example 2
<FilesMatch "\.(flv|ico)$">
Header set Cache-Control "max-age=29030400, public"
</FilesMatch>
<FilesMatch "\.(pdf|swf)$">
Header set Cache-Control "max-age=3600, public"
</FilesMatch>
<FilesMatch "\.(html)$">
Header set Expires "Fri, 04 Aug 1978 12:00:00 GMT"
Header set Cache-Control "no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, no-transform"
Header set Pragma "no-cache"
</FilesMatch>
<FilesMatch "\.(js|css|xml)$">
Header set Cache-Control "max-age=3600, private, must-revalidate"
</FilesMatch>
<FilesMatch "\.(jpg|jpeg|png|txt|gif)$">
Header set Cache-Control "max-age=3600, public"
</FilesMatch>
This solution is the best, a hybrid utilizing both modules
# Turn on Expires and set default to 0
ExpiresActive On
ExpiresDefault A0
# Set up caching on media files for 1 year (forever?)
<FilesMatch "\.(ico|flv|pdf|mov|mp3|wmv|ppt)$">
ExpiresDefault A29030400
Header append Cache-Control "public"
</FilesMatch>
# Set up caching on media files for 1 week
<FilesMatch "\.(gif|jpg|jpeg|png|swf)$">
ExpiresDefault A604800
Header append Cache-Control "public, proxy-revalidate"
</FilesMatch>
# Set up 2 Hour caching on commonly updated files
<FilesMatch "\.(xml|txt|html|js|css)$">
ExpiresDefault A7200
Header append Cache-Control "private, proxy-revalidate, must-revalidate"
</FilesMatch>
# Force no caching for dynamic files
<FilesMatch "\.(php|cgi|pl|htm)$">
ExpiresDefault A0
Header set Cache-Control "no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, no-transform"
Header set Pragma "no-cache"
</FilesMatch>
NOTE: Using FilesMatch and Files in htaccess (http://www.askapache.com/2006/htaccess/using-filesmatch-and-files-in-htaccess.html)
Here is what the Headers look like when downloading a JPEG image, with this caching scheme implemented, and without.
JPEG WITHOUT CACHING
Last-Modified: Wed, 22 Feb 2006 12:16:56 GMT
ETag: "b57d54-45e7"
Accept-Ranges: bytes
Content-Length: 17895
Connection: close
Content-Type: image/jpeg
WITH CACHING
Cache-Control: max-age=2592000
Expires: Tue, 28 Mar 2006 16:23:52 GMT
Last-Modified: Wed, 22 Feb 2006 12:16:56 GMT
ETag: "b57d54"
Accept-Ranges: bytes
Content-Length: 17895
Connection: close
Content-Type: image/jpeg
Content-Language: en
More examples and detailed explanations here (http://www.askapache.com/2006/htaccess/speed-up-sites-with-htaccess-caching.html).
Webmasters Caching Tutorial (http://www.askapache.com/2007/webmaster/caching-tutorial-for-webmasters.html).
Warnings
You should never need to go over a MONTH. (I go a year for .pdf, .ico, .flv, .mp3)
And once you set an expiration date and a visitor sees it, the visitor will not even attempt to check for a new version until that expiration.. so start out with small expiration lengths!
Note that despite its name, "no-cache" does not prevent caching. It is taken to mean that the object must be revalidated. But then we add another layer of nonsense, in that this is considered a "weak revalidation" request, and caches can ignore it under very-poorly-defined circumstances. In order to force "strong revalidation," you have to use "no-cache, must revalidate". But even then... Large and big-headed ISPs like AOL won't obey that strong revalidation, so you have to pound them over the head with, "private, must-revalidate", telling them not to cache the object in their network caches at all.
Does my Apache Server have the modules?
The modules need to be built into Apache; although they are included in the distribution, they are not turned on by default. To find out if the
modules are enabled in your server, find the httpd binary and run httpd -l; this should print a list of the available modules. The modules we’re
looking for are mod_expires and mod_headers.
If they aren’t available, and you have administrative access, you can recompile Apache to include them. This can be done either by uncommenting the appropriate lines in the Configuration file, or using the -enable-module=expires and -enable-module=headers
#=============================================================================#
# TIME CHEAT SHEET
#=============================================================================#
# 300 5 M # 604800 1 W
# 2700 45 M # 1814400 3 W
# 3600 1 H # 2419200 1 M
# 54000 15 H # 14515200 6 M
# 86400 1 D # 26611200 11 M
# 518400 6 D # 29030400 1 Y (never expire)
Browsers automatically cache files, but they do so in a "must-revalidate" way. That means that they cache the files on your server, but every single time you use that cache by going back to the cached page, your browser send a 301 If-Modified header to check and see if you have modified the cached file since that time. Basically most images, css, javascript, and other files can be optimized for faster loading by telling your visitors browsers to cache them for a certain period of time. The default behaviour is to check the last-modified and/or the Etag headers of the file EVERY time it is requested.
By employing the methods in this article you can totally eliminate these unneccessary 301s and dramatically speed up the loading and rendering of your site. When you implement the caching method described in this article, you can specify that certain files or filetypes be cached for a specific amount of time. These files are then cached by your site visitors and they do not send the If-Modified-Since until the set cache time has completed.
The first solution uses the Apache Module mod_expires 1.3 (http://www.askapache.com/docs/1.3/mod/mod_expires.html)|2.0 (http://www.askapache.com/docs/2.0/mod/mod_expires.html)|2.2 (http://www.askapache.com/docs/2.2/mod/mod_expires.html)
ExpiresActive On
#every filetype not listed below gets cached 300
ExpiresDefault A300
# YEAR
ExpiresByType image/x-icon A29030400
# MONTH
ExpiresByType video/x-flv A2419200
ExpiresByType application/pdf A2419200
# WEEK
ExpiresByType image/gif A604800
ExpiresByType image/png A604800
ExpiresByType image/jpeg A604800
ExpiresByType application/x-shockwave-flash A604800
#hour
ExpiresByType application/x-javascript A3600
ExpiresByType application/xml A3600
ExpiresByType text/css A3600
ExpiresByType text/plain A3600
#5 minutes
ExpiresByType text/html A300
The second solution uses mod_headers 1.3 (http://www.askapache.com/docs/1.3/mod/mod_headers.html)|2.0 (http://www.askapache.com/docs/2.0/mod/mod_headers.html)|2.2 (http://www.askapache.com/docs/2.2/mod/mod_headers.html)
Example 1
# YEAR
<FilesMatch "\.(ico)$">
Header set Cache-Control "max-age=29030400, public"
</FilesMatch>
# MONTH
<FilesMatch "\.(flv|pdf)$">
Header set Cache-Control "max-age=2419200, public"
</FilesMatch>
# WEEK
<FilesMatch "\.(swf|css)$">
Header set Cache-Control "max-age=604800, private, must-revalidate"
</FilesMatch>
# NEVER CACHE
<FilesMatch "\.(html|cgi|php|htm)$">
Header set Expires "Fri, 04 Aug 1978 12:00:00 GMT"
Header set Cache-Control "no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, no-transform"
Header set Pragma "no-cache"
</FilesMatch>
Example 2
<FilesMatch "\.(flv|ico)$">
Header set Cache-Control "max-age=29030400, public"
</FilesMatch>
<FilesMatch "\.(pdf|swf)$">
Header set Cache-Control "max-age=3600, public"
</FilesMatch>
<FilesMatch "\.(html)$">
Header set Expires "Fri, 04 Aug 1978 12:00:00 GMT"
Header set Cache-Control "no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, no-transform"
Header set Pragma "no-cache"
</FilesMatch>
<FilesMatch "\.(js|css|xml)$">
Header set Cache-Control "max-age=3600, private, must-revalidate"
</FilesMatch>
<FilesMatch "\.(jpg|jpeg|png|txt|gif)$">
Header set Cache-Control "max-age=3600, public"
</FilesMatch>
This solution is the best, a hybrid utilizing both modules
# Turn on Expires and set default to 0
ExpiresActive On
ExpiresDefault A0
# Set up caching on media files for 1 year (forever?)
<FilesMatch "\.(ico|flv|pdf|mov|mp3|wmv|ppt)$">
ExpiresDefault A29030400
Header append Cache-Control "public"
</FilesMatch>
# Set up caching on media files for 1 week
<FilesMatch "\.(gif|jpg|jpeg|png|swf)$">
ExpiresDefault A604800
Header append Cache-Control "public, proxy-revalidate"
</FilesMatch>
# Set up 2 Hour caching on commonly updated files
<FilesMatch "\.(xml|txt|html|js|css)$">
ExpiresDefault A7200
Header append Cache-Control "private, proxy-revalidate, must-revalidate"
</FilesMatch>
# Force no caching for dynamic files
<FilesMatch "\.(php|cgi|pl|htm)$">
ExpiresDefault A0
Header set Cache-Control "no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, no-transform"
Header set Pragma "no-cache"
</FilesMatch>
NOTE: Using FilesMatch and Files in htaccess (http://www.askapache.com/2006/htaccess/using-filesmatch-and-files-in-htaccess.html)
Here is what the Headers look like when downloading a JPEG image, with this caching scheme implemented, and without.
JPEG WITHOUT CACHING
Last-Modified: Wed, 22 Feb 2006 12:16:56 GMT
ETag: "b57d54-45e7"
Accept-Ranges: bytes
Content-Length: 17895
Connection: close
Content-Type: image/jpeg
WITH CACHING
Cache-Control: max-age=2592000
Expires: Tue, 28 Mar 2006 16:23:52 GMT
Last-Modified: Wed, 22 Feb 2006 12:16:56 GMT
ETag: "b57d54"
Accept-Ranges: bytes
Content-Length: 17895
Connection: close
Content-Type: image/jpeg
Content-Language: en
More examples and detailed explanations here (http://www.askapache.com/2006/htaccess/speed-up-sites-with-htaccess-caching.html).
Webmasters Caching Tutorial (http://www.askapache.com/2007/webmaster/caching-tutorial-for-webmasters.html).
Warnings
You should never need to go over a MONTH. (I go a year for .pdf, .ico, .flv, .mp3)
And once you set an expiration date and a visitor sees it, the visitor will not even attempt to check for a new version until that expiration.. so start out with small expiration lengths!
Note that despite its name, "no-cache" does not prevent caching. It is taken to mean that the object must be revalidated. But then we add another layer of nonsense, in that this is considered a "weak revalidation" request, and caches can ignore it under very-poorly-defined circumstances. In order to force "strong revalidation," you have to use "no-cache, must revalidate". But even then... Large and big-headed ISPs like AOL won't obey that strong revalidation, so you have to pound them over the head with, "private, must-revalidate", telling them not to cache the object in their network caches at all.
Does my Apache Server have the modules?
The modules need to be built into Apache; although they are included in the distribution, they are not turned on by default. To find out if the
modules are enabled in your server, find the httpd binary and run httpd -l; this should print a list of the available modules. The modules we’re
looking for are mod_expires and mod_headers.
If they aren’t available, and you have administrative access, you can recompile Apache to include them. This can be done either by uncommenting the appropriate lines in the Configuration file, or using the -enable-module=expires and -enable-module=headers
#=============================================================================#
# TIME CHEAT SHEET
#=============================================================================#
# 300 5 M # 604800 1 W
# 2700 45 M # 1814400 3 W
# 3600 1 H # 2419200 1 M
# 54000 15 H # 14515200 6 M
# 86400 1 D # 26611200 11 M
# 518400 6 D # 29030400 1 Y (never expire)