Mobile app version of vmapp.org
Login or Join
Shelley277

: Image max-age / cache-control not being set In order to speed up my site Telium I created the .htaccess below. I have a lot of large images on my site so I want browsers to cache as much

@Shelley277

Posted in: #Browsers #Cache #Images

In order to speed up my site Telium I created the .htaccess below. I have a lot of large images on my site so I want browsers to cache as much as possible. However, when I browse to my web site with the developer tools open (in Chrome), I see that all of the images on my pages are being re-downloaded every time I refresh.

My .htaccess is located in the root of the web site, and looks like this:

# BEGIN Expire headers
<ifModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 5 seconds"
ExpiresByType image/x-icon "access plus 2592000 seconds"
ExpiresByType image/jpeg "access plus 2592000 seconds"
ExpiresByType image/png "access plus 2592000 seconds"
ExpiresByType image/gif "access plus 2592000 seconds"
ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds"
ExpiresByType text/css "access plus 604800 seconds"
ExpiresByType text/javascript "access plus 216000 seconds"
ExpiresByType application/javascript "access plus 216000 seconds"
ExpiresByType application/x-javascript "access plus 216000 seconds"
ExpiresByType text/html "access plus 600 seconds"
ExpiresByType application/xhtml+xml "access plus 600 seconds"
</ifModule>
# END Expire headers
<ifModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/xml text/css text/plain
AddOutputFilterByType DEFLATE image/svg+xml application/xhtml+xml application/xml
AddOutputFilterByType DEFLATE application/rdf+xml application/rss+xml application/atom+xml
AddOutputFilterByType DEFLATE text/javascript application/javascript application/x-javascript application/json
AddOutputFilterByType DEFLATE application/x-font-ttf application/x-font-otf
AddOutputFilterByType DEFLATE font/truetype font/opentype
</ifModule>
# BEGIN Cache-Control Headers
<ifModule mod_headers.c>
<filesMatch ".(ico|jpe?g|png|gif|swf)$">
Header set Cache-Control "public"
</filesMatch>
<filesMatch ".(css)$">
Header set Cache-Control "public"
</filesMatch>
<filesMatch ".(js)$">
# was private
Header set Cache-Control "public"
</filesMatch>
<filesMatch ".(x?html?|php)$">
Header set Cache-Control "private, must-revalidate"
</filesMatch>
</ifModule>
# END Cache-Control Headers


Here is an example of the response headers associated with an image retrieved every time I refresh:

Accept-Ranges:bytes
Cache-Control:public
Connection:Keep-Alive
Content-Length:75149
Content-Type:image/jpeg
Date:Thu, 28 May 2015 12:56:46 GMT
ETag:"a9e0dd3-1258d-516beac088af3"
Expires:Sat, 27 Jun 2015 12:56:46 GMT
Keep-Alive:timeout=5
Last-Modified:Sat, 23 May 2015 12:11:09 GMT
Server:Apache/2.4.12 (Unix) OpenSSL/1.0.1e-fips mod_bwlimited/1.4 mod_fcgid/2.3.10-dev


Can someone suggest what I need to change to make the browser cache these images (and text)?



Update: After adding max-age the new header is:

Accept-Ranges:bytes
Cache-Control:public, max-age=2592000
Connection:Keep-Alive
Content-Length:118966
Content-Type:image/jpeg
Date:Thu, 28 May 2015 20:11:33 GMT
ETag:"a9e0de5-1d0b6-516bead2e811c"
Expires:Sat, 27 Jun 2015 20:11:33 GMT
Keep-Alive:timeout=5
Last-Modified:Sat, 23 May 2015 12:11:28 GMT
Server:Apache/2.4.12 (Unix) OpenSSL/1.0.1e-fips mod_bwlimited/1.4 mod_fcgid/2.3.10-dev

10.03% popularity Vote Up Vote Down


Login to follow query

More posts by @Shelley277

3 Comments

Sorted by latest first Latest Oldest Best

 

@Rambettina238

I think this is normal behaviour when you click refresh - you're telling the browser to grab a fresh copy of the resources from the server. If you want to see it working, click on a link to another page and then click a link that takes you back to the page you were on.

Edit: Screenshot from Chrome developer tools, see all the '(from cache)' entries.

10% popularity Vote Up Vote Down


 

@Annie201

You should change...

Header set Cache-Control "public"


...to...

Header set Cache-Control "max-age=x"


...but replace x with the number of seconds you want any browser that supports HTTP 1.1 to cache the item. The reason why I removed "public" is because public is the default scope in which caching is applied to (meaning it is applied to browsers and proxies in-between).

The if-modified checks and etags as Richhallstoke suggests is useful but requests are still made to the server even to receive a 304 response. Caching with a maximum age set (whether through expires header or cache-control's max-age) means the browser will use the local cache as much as possible until the defined age is reached or a forced refresh is made. This means more bandwidth savings for the client.

10% popularity Vote Up Vote Down


 

@Cugini213

There are two options really:


You can remove the Last-Modified and ETag headers then the web browsers won't attempt to see if there's a newer version available and will just trust the Expires date/time you have supplied.
You can check if HTTP_IF_MODIFIED_SINCE matches the last modified datestamp or if HTTP_IF_NONE_MATCH matches the ETag and then return a HTTP/1.1 304 Not Modified header instead of whatever resource was requested.

I'm not aware of a method to achieve this directly from in an Apache .htaccess configuration file however you can do this in PHP, see example source code in my answer here:
weird results from tests when trying to serve a fast image download pageā€¦ why?


Some people have strong opinion that its best to let the browser manage the caching, and just get rid of the headers (option 1) however if you change your website before the Expires datestamp then anyone accessing resources could see their old cached versions against new HTML content until hitting Ctrl+F5 to force a refresh of all files required by the page. Checking the headers (option 2) and only returning content if a newer version is available is how the HTTP protocol was designed to be used efficiently.

In times gone by when each resource request required a separate network connection and browsers would only use a maximum of 10 concurrent connections to the same server I can understand this could cause delays in page load times, however provided your webserver is configured to allow persistent connections then web browsers will chain resource requests together and send them one after the other very quickly on the same connection.

10% popularity Vote Up Vote Down


Back to top | Use Dark Theme