14. November 2008, 16:57, by Leo Büttiker

Clientside Cache Control

Users hate your cache

Users don’t like caching! They want to see the changes immediately. Otherwise they get confused and write you bug tickets or flame mails. But if you do not use caching the user comes and make your CPU’s burning. If your site is down you not only get mails from your users, but also from your management.

We worked hard on the right caching strategy over months now. But there are still caches that do not get invalidated right or are cached too long and we still get complaints from our users. So we decided to integrate a feature that allows certain users to invalidate the cache on the server side. The first idea was to add a link to every page that will append a GET-parameter to the site and then avoid the cache.

Thanks to a bug ticket I remembered that certain browsers could force squid to reload the resources. The trick is that the HTTP/1.1-protocol has some features to control caching. If you press ctrl+F5 in your browser some of this features are triggered and sent over the wire in the http-request-header. I found a great article about headers in different browsers, unfortunately it’s not correct in every case.

Request Headers in PHP

So I had to find out what these browsers in fact are sending. Sure – you could find out with a sniffer, but as I needed this data in my script anyway I tried to get them from php. As long as your php installation does run as an apache module this is pretty easy: With apache_request_header() you get an array with all header information. I did add them to our debug window and I did get something like:

Trevi_Debug_Dump::dump(array(8), 'headers') 
  'Accept' => string '*/*' (length=3)
  'Accept-Language' => string 'de-ch' (length=5)
  'Accept-Encoding' => string 'gzip, deflate' (length=13)
  'User-Agent' => string 'Mozilla/4.0 ([...]; InfoPath.1)' (length=86)
  'Host' => string 'ch.sb2.leo.dev.tilllate.com' (length=27)
  'Connection' => string 'Keep-Alive' (length=10)
  'Cache-Control' => string 'no-cache' (length=8)
  'Cookie' => string '__utma=[...]' (length=769)

Browser Magic

So I tried this for different browsers. Unfortunately it’s specified nowhere what a browser has to send in which situation.

Internet Explorer 6 and 7 do both send only cache refresh hints on ctrl+F5. On ctrl+F5 they both send the header field ‘Cache-Control’ set to ‘no-cache’.

Firefox 3 do send the header field ‘Cache-Control’ with the value ‘max-age=0′ if the user press f5. If you press ctrl+f5 Firefox sends the ‘Cache-Control’ with ‘no-cache’ (hey it do the same as IE!) and send also a field ‘Pragma’ which is also set to ‘no-cache’.

Firefox 2 does send the header field ‘Cache-Control’ with the value ‘max-age=0′ if the user press f5. ctrl+f5 does not work.

Opera/9.62 does send ‘Cache-Control’ with the value ‘max-age=0′ after f5 and ctrl+f5 does not work.

Safari 3.1.2 behaves like Opera above.

Chrome does something quite different: ‘Cache-Control’ is always set to ‘max-age=0′, no matter if you press enter, f5 or ctrl+f5. Except if you start Chrome and enter the url and press enter.

Browser Wars

Somehow it does look like there is still war outside. The Browser War is not over yet! Nearly every browser seams to interpret the http standard a bit different. This makes implementing software for the web quite hard, Chrome does not help at all at this point.

As my cache-invalidation-implementation is implemented only for a small user base I will make it only work for IE and FF 3.

Filed under: PHP,Programming


  1. Surely Etags & Last-Modifieds are preferable to this, and allow the client browser to ask if its cached copy is still valid.

    Comment by Ren — 14. November 2008 @ 17:57

  2. Personally I simply notify users when some of their submitted content is not shown yet due to caching, I’ve yet to hear any complaints, same goes for downtime, so long as they know why things are happening the way they are they’re usually OK with it.

    Feedback to your users can save you lots of complicated work. ;)

    Comment by Martin F — 14. November 2008 @ 19:19

  3. I believe FF2 and FF3 also use Ctlr+Shift+r to bust the cache.

    Comment by Micah — 15. November 2008 @ 00:53

  4. For FireFox, you can also force a full refresh by holding down shift and clicking on the refresh button.

    Comment by Bryan Migliorisi — 16. November 2008 @ 19:23

  5. @Martin F.: I completly agree on this. But if you use Memcache for caching you have alot of different values and it’s hard to comunicate this to the user.
    @Micah & Bryan: Yes, I tried it on FF3. Both methods force FF to send ‘Cache-Control’ and ‘Pragma’ with no-cache.

    Comment by leo — 17. November 2008 @ 10:04

  6. You can check your client headers at: view request headers

    Comment by sergio — 17. November 2008 @ 18:08

  7. cool how you censor your home directory but not the Host header ;-)

    Comment by Jiayong Ou — 17. November 2008 @ 20:33

  8. Man, we’re still dealing with browser wars…what a joke. I would be ok with it if everyone adhered to the W3C protocol and then added bells and whistles to make their browser ‘better’, but designing for multiple forms is crazy.

    Comment by Acai — 26. November 2008 @ 09:41

  9. [...] techblog.tilllate.com gab es vor kurzer Zeit einen recht interessanten Ansatz zur Cache-Kontrolle durch den User. Dieses ist eine deutsche Erklärung dazu, die noch einen kleinen Schritt weiter [...]

    Pingback by Clientside Cache Control - Webboarder — 27. November 2008 @ 19:01

  10. I personally find firefox to be the most effective website with the smallest cache. Also as stated before you can do a force full refresh by holding down shift and clicking refresh.

    Comment by Eric Bence — 11. January 2009 @ 20:40

  11. Cache in FF really sucks! Why the hell safari does so well?

    Comment by Gomer — 2. April 2009 @ 22:25

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

© 2014 tilllate Schweiz AG - Powered by WordPress