Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forcing the browser to reload css when it has been updated

When I update a css file on the server, many client browsers will continue to load pages using the old cached css file for quite some time.

After searching through many posts and putting different ideas together, I have come up with what seems to be the simplest and cheapest approach.

Where any css file is being linked, append the href with the timestamp of the last modified date of the file, like this:

<link rel="stylesheet" type="text/css" href="main.css?t=<?=filemtime('main.css')?>" />

I am using CakePHP, so what I do in the layout file is this:

  <? $t = filemtime(CSS . 'main.css'); ?>
  <?=$html->css("schedule.css?t={$t}") ?>

So the link to the css file has an extra tag on the end, but it stays the same as long as the file has not been modified. This means that the browser will be able to cache it as usual. As soon as the file is modified, however, the link will change and the browser will not miss a beat.

Still with this method, one is left feeling a bit dirty for using something for what it is not intended. There is no use for the "message" that is being sent, in the sense that the content of the message matters, other than identifying it's existence.

Here are my questions:

  1. Can it be acknowledged that there is a risk of the client seeing revised HTML with out of date stylesheets (or javascript for that matter) from the browser cache?
  2. Is this a hack or a legitimate solution?
  3. Is there a better solution?
like image 886
Jason Galuten Avatar asked Feb 21 '23 19:02

Jason Galuten


1 Answers

I don't think there's any problem with your approach. More commonly, this is called cache busting or cache invalidation.

However, because you are using a url such as: http://site.com/assets/mystyle.css?29320202020, there might be issues with CDNs. The CDN will see that GET parameter and think that its a dynamic request, so it will ask your servers for the file, which defeats the purpose of having a cached copy in the CDN.

Why I do is that I include the cache busting parameter in my filename: http://site.com/assets/mystyle.2390202202.css. I am using the excellent Assetic library to do this and have just written some simple code so that my templates know it requires mystyle.css and mystyle.2390202202.css is generated by Assetic on the fly and inserted into the template.

This approach should get you cache busting funcionality while dealing with CDNs nicely.


Other possible solutions:

  • ETags: The browser will send a request to the server with the ETag (can be thinked of as a hash of the file), and the server will respond with a not modified header response if the file has not changed. Downside: A HTTP request still needs to be made.

  • Set an expires header: The server will tell the browser that the file will expire at a certain date, and if it is not that date yet, the browser will not request a copy from the server and use its local cached copy. Downside: If the file on the server changes before the date, the browser's user will need to manually do a hard refresh.

This is why I prefer to just use a cache busting parameter: I can set the expires header for the file to expire in 5 years. And the browser should never make an http request for that file, unless I update the file and change the cache busting parameter.

like image 69
F21 Avatar answered Mar 24 '23 06:03

F21