I have a system where cache max-age is set to 0 and there is problem, when I have made some changes in my style.css fail the changes dont apear to client. Browser will use the old cached version of css.
I have simple question: Does naming css file as style.css?123 will be cached as a new?
Yes, adding a unique query string to the resource's URI will force the client to fetch a "fresh" version (since the client doesn't know that it's merely an update of a previously cached resource). This is known as fingerprinting and you typically use a timestamp or an incrementing version number1 of the CSS file.
Google Web Fundamentals has a great article on HTTP cache optimization. Especially the section titled "Invalidating and updating cached responses:"
How do you get the best of both worlds: client-side caching and quick updates? You change the URL of the resource and force the user to download the new response whenever its content changes. Typically, you do this by embedding a fingerprint of the file, or a version number, in its filename—for example, style.x234dff.css.
Do note, that the fingerprint does not need to be a sequential number. Any value – hash, version, etc. – will do as long as the risk of collisions is limited.
1) This is what's done here on SO, e.g. http://sstatic.net/js/global-login.js?v=12
You can append a unique query string, although this will use bandwidth.
You can rename your CSS file every time you make a change, IE:
main-v1.css
main-v2.css
main-v3.css
And then re-reference it in your pages. This saves bandwidth and forces browsers to reload it.
yes, appending a querystring parameter in each style.css file will force it to cache again.
because browser caches each static component with its url, so when url is changed, the new file will be cached.
You can trick the browser into thinking it's a new stylesheet every second by timestamping your CSS:
<link rel="stylesheet" type="text/css" href="style.css?<?php echo date('l jS \of F Y h:i:s A'); ?>" />
Which will give you this:
<link rel="stylesheet" type="text/css" href="style.css?Thursday 24th of April 2008 04:45:21 PM" />
Taken from: Can We Prevent CSS Caching?
Using .htaccess file, you can define caching control on you files with special extensions.
You could include the following code in a .htaccess file:
<FilesMatch "\.(css)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
For more information about .htaccess file, see Apache .htaccess Guide
Related
We want to cache bust on production deploys, but not waste a bunch of time off the bat figuring out a system for doing so. My thought was to apply a param to the end of css and js files with the current version number:
<link rel="stylesheet" href="base_url.com/file.css?v=1.123"/>
Two questions: Will this effectively break the cache? Will the param cause the browser to then never cache the response from that url since the param indicates that this is dynamic content?
The param ?v=1.123 indicates a query string, and the browser will therefore think it is a new path from, say, ?v=1.0. Thus causing it to load from file, not from cache. As you want.
And, the browser will assume that the source will stay the same next time you call ?v=1.123 and should cache it with that string. So it will remain cached, however your server is set up, until you move to ?v=1.124 or so on.
Two questions: Will this effectively break the cache?
Yes. Even Stack Overflow use this method, although I remember that they (with their millions of visitors per day and zillions of different client and proxy versions and configurations) have had some freak edge cases where even this was not enough to break the cache. But the general assumption is that this will work, and is a suitable method to break caching on clients.
Will the param cause the browser to then never cache the response from that url since the param indicates that this is dynamic content?
No. The parameter will not change the caching policy; the caching headers sent by the server still apply, and if it doesn't send any, the browser's defaults.
It is safer to put the version number in the actual filename. This allows multiple versions to exist at once so you can roll out a new version and if any cached HTML pages still exist that are requesting the older version, they will get the version that works with their HTML.
Note, in one of the largest versioned deployments anywhere on the internet, jQuery uses version numbers in the actual filename and it safely allows multiple versions to co-exist without any special server-side logic (each version is just a different file).
This busts the cache once when you deploy new pages and new linked files (which is what you want) and from then on those versions can be effectively cached (which you also want).
As others have said, cache busting with a query param is usually considered a Bad Idea (tm), and has been for a long time. It's better to reflect the version in the file name. Html5 Boilerplate recommends against using the query string, among others.
That said, of the recommendations I have seen which cited a source, all seem to take their wisdom from a 2008 article by Steve Souders. His conclusions are based on the behaviour of proxies at the time, and they may or may not be relevant these days. Still, in the absence of more current information, changing the file name is the safe option.
It will bust the cache once, after the client has downloaded the resource every other response will be served from client cache unless:
the v parameter is updated.
the client clears their cache
In general this should be fine, but it's possible for this to not work if there is an intermediate cache (a proxy) that is configured to ignore the request parameters.
For example, if you are serving static content through Akamai CDN, it can be configured to ignore request parameters to prevent cache busting using this method.
It very much depends on quite how robust you want your caching to be. For example, the squid proxy server (and possibly others) defaults to not caching URLs served with a querystring - at least, it did when that article was written. If you don't mind certain use cases causing unnecessary cache misses, then go ahead with query params. But it's very easy to set up a filename-based cache-busting scheme which avoids this problem.
Found a comparison of the 2 techniques (query string vs file name) here:
Version as a querystring has two problems.
First, it may not always be a browser that implements caching through which we need to bust. It is said that certain (possibly older) proxies do ignore the querystring with respect to their caching behavior.
Second, in certain more complex deployment scenarios, where you have multiple frontend and/or multiple backend servers, an upgrade is anything but instantaneous. You need to be able to serve both the old and the new version of your assets at the same time. See for example how this affects you when using Google App Engine.
Another similar approach is to use htaccess mod_rewrite to ignore part of the path when serving the files. Your never-cached index page references the latest path to the files.
From a development perspective it's as easy as using params for the version number, but it's as robust as the filename approach.
Use the ignored part of the path for the version number, and the server just ignores it and serves the uncached file.
1.2.3/css/styles.css serves the same file as css/styles.css since the first directory is stripped and ignored by the htaccess file
Including versioned files
<?php
$version = "1.2.3";
?>
<html>
<head>
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
<link rel="stylesheet" type="text/css" href="<?php echo $version ?>/css/styles.css">
</head>
<body>
<script src="<?php echo $version ?>/js/main.js"></script>
</body>
</html>
Note that this approach means you need to disable caching of your index page - Using <meta> tags to turn off caching in all browsers?
.htaccess file
RewriteEngine On
# if you're requesting a file that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-f
# likewise if a directory that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise, rewrite foo/bar/baz to bar/baz - ignore the first directory
RewriteRule ^[^/]+/(.+)$ $1 [L]
You could take the same approach on any server platform that allows url rewriting
(rewrite condition adapted from mod_rewrite - rewrite directory to query string except /#!/)
... and if you need cache busting for your index page / site entry point, you could always use JavaSript to refresh it.
Hope this should help you to inject external JS file
<script type="text/javascript">
var cachebuster = Math.round(new Date().getTime() / 1000);
document.write('<scr'+'ipt type="text/javascript" src="external.js?cb=' +cachebuster+'"></scr' + 'ipt>');
</script>
Source - Cachebuster code in JavaScript
<script type="text/javascript">
// front end cache bust
var cacheBust = ['js/StrUtil.js', 'js/protos.common.js', 'js/conf.js', 'bootstrap_ECP/js/init.js'];
for (i=0; i < cacheBust.length; i++){
var el = document.createElement('script');
el.src = cacheBust[i]+"?v=" + Math.random();
document.getElementsByTagName('head')[0].appendChild(el);
}
</script>
<script>
var storedSrcElements = [
"js/exampleFile.js",
"js/sampleFile.js",
"css/style.css"
];
var head= document.getElementsByTagName('head')[0];
var script;
var link;
var versionNumberNew = 4.6;
for(i=0;i<storedSrcElements.length;i++){
script= document.createElement('script');
script.type= 'text/javascript';
script.src= storedSrcElements[i] + "?" + versionNumberNew;
head.appendChild(script);
}
</script>
### Change the version number (versionNumberNew) when you want the new files to be loaded ###
We want to cache bust on production deploys, but not waste a bunch of time off the bat figuring out a system for doing so. My thought was to apply a param to the end of css and js files with the current version number:
<link rel="stylesheet" href="base_url.com/file.css?v=1.123"/>
Two questions: Will this effectively break the cache? Will the param cause the browser to then never cache the response from that url since the param indicates that this is dynamic content?
The param ?v=1.123 indicates a query string, and the browser will therefore think it is a new path from, say, ?v=1.0. Thus causing it to load from file, not from cache. As you want.
And, the browser will assume that the source will stay the same next time you call ?v=1.123 and should cache it with that string. So it will remain cached, however your server is set up, until you move to ?v=1.124 or so on.
Two questions: Will this effectively break the cache?
Yes. Even Stack Overflow use this method, although I remember that they (with their millions of visitors per day and zillions of different client and proxy versions and configurations) have had some freak edge cases where even this was not enough to break the cache. But the general assumption is that this will work, and is a suitable method to break caching on clients.
Will the param cause the browser to then never cache the response from that url since the param indicates that this is dynamic content?
No. The parameter will not change the caching policy; the caching headers sent by the server still apply, and if it doesn't send any, the browser's defaults.
It is safer to put the version number in the actual filename. This allows multiple versions to exist at once so you can roll out a new version and if any cached HTML pages still exist that are requesting the older version, they will get the version that works with their HTML.
Note, in one of the largest versioned deployments anywhere on the internet, jQuery uses version numbers in the actual filename and it safely allows multiple versions to co-exist without any special server-side logic (each version is just a different file).
This busts the cache once when you deploy new pages and new linked files (which is what you want) and from then on those versions can be effectively cached (which you also want).
As others have said, cache busting with a query param is usually considered a Bad Idea (tm), and has been for a long time. It's better to reflect the version in the file name. Html5 Boilerplate recommends against using the query string, among others.
That said, of the recommendations I have seen which cited a source, all seem to take their wisdom from a 2008 article by Steve Souders. His conclusions are based on the behaviour of proxies at the time, and they may or may not be relevant these days. Still, in the absence of more current information, changing the file name is the safe option.
It will bust the cache once, after the client has downloaded the resource every other response will be served from client cache unless:
the v parameter is updated.
the client clears their cache
In general this should be fine, but it's possible for this to not work if there is an intermediate cache (a proxy) that is configured to ignore the request parameters.
For example, if you are serving static content through Akamai CDN, it can be configured to ignore request parameters to prevent cache busting using this method.
It very much depends on quite how robust you want your caching to be. For example, the squid proxy server (and possibly others) defaults to not caching URLs served with a querystring - at least, it did when that article was written. If you don't mind certain use cases causing unnecessary cache misses, then go ahead with query params. But it's very easy to set up a filename-based cache-busting scheme which avoids this problem.
Found a comparison of the 2 techniques (query string vs file name) here:
Version as a querystring has two problems.
First, it may not always be a browser that implements caching through which we need to bust. It is said that certain (possibly older) proxies do ignore the querystring with respect to their caching behavior.
Second, in certain more complex deployment scenarios, where you have multiple frontend and/or multiple backend servers, an upgrade is anything but instantaneous. You need to be able to serve both the old and the new version of your assets at the same time. See for example how this affects you when using Google App Engine.
Another similar approach is to use htaccess mod_rewrite to ignore part of the path when serving the files. Your never-cached index page references the latest path to the files.
From a development perspective it's as easy as using params for the version number, but it's as robust as the filename approach.
Use the ignored part of the path for the version number, and the server just ignores it and serves the uncached file.
1.2.3/css/styles.css serves the same file as css/styles.css since the first directory is stripped and ignored by the htaccess file
Including versioned files
<?php
$version = "1.2.3";
?>
<html>
<head>
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
<link rel="stylesheet" type="text/css" href="<?php echo $version ?>/css/styles.css">
</head>
<body>
<script src="<?php echo $version ?>/js/main.js"></script>
</body>
</html>
Note that this approach means you need to disable caching of your index page - Using <meta> tags to turn off caching in all browsers?
.htaccess file
RewriteEngine On
# if you're requesting a file that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-f
# likewise if a directory that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise, rewrite foo/bar/baz to bar/baz - ignore the first directory
RewriteRule ^[^/]+/(.+)$ $1 [L]
You could take the same approach on any server platform that allows url rewriting
(rewrite condition adapted from mod_rewrite - rewrite directory to query string except /#!/)
... and if you need cache busting for your index page / site entry point, you could always use JavaSript to refresh it.
Hope this should help you to inject external JS file
<script type="text/javascript">
var cachebuster = Math.round(new Date().getTime() / 1000);
document.write('<scr'+'ipt type="text/javascript" src="external.js?cb=' +cachebuster+'"></scr' + 'ipt>');
</script>
Source - Cachebuster code in JavaScript
<script type="text/javascript">
// front end cache bust
var cacheBust = ['js/StrUtil.js', 'js/protos.common.js', 'js/conf.js', 'bootstrap_ECP/js/init.js'];
for (i=0; i < cacheBust.length; i++){
var el = document.createElement('script');
el.src = cacheBust[i]+"?v=" + Math.random();
document.getElementsByTagName('head')[0].appendChild(el);
}
</script>
<script>
var storedSrcElements = [
"js/exampleFile.js",
"js/sampleFile.js",
"css/style.css"
];
var head= document.getElementsByTagName('head')[0];
var script;
var link;
var versionNumberNew = 4.6;
for(i=0;i<storedSrcElements.length;i++){
script= document.createElement('script');
script.type= 'text/javascript';
script.src= storedSrcElements[i] + "?" + versionNumberNew;
head.appendChild(script);
}
</script>
### Change the version number (versionNumberNew) when you want the new files to be loaded ###
So I'm having this really weird bug with my new server where the CSS won't update in the browser. Refreshing and clearing the cache doesn't work. I then opened up FileZilla to see if the updated CSS file is actually being uploaded to server using FTP, which it is, and then when I drag a copy of the css file to my desktop, the css file magically updates. The PHP file updates just fine.
Here's how I include the css: <link rel="stylesheet" type="text/css" href="css/stylesheet.css">
I have no idea what is happening and how to fix this so any help would be greatly appreciated!
You could have any number of issues, but I'd like to point out a cool tip when using Chrome.
On your page, with the developer tools open if you press and hold the reload button you get a great option to clear the cache and hard reload!
This is very handy to make sure you have the "freshest" copy while developing.
Update:
As for your scenario (after reading updates) it sounds like an HTTP header issue with your CSS file.
Check what HTTP headers are being sent with your CSS file response. If you are not specifying a cache header it will likely try to cache for you. Set an expires header (in the past) when in development, but far in the future when in production. In the Network tab of your developer tools (most browsers) you should be able to see these headers, or you can use a too like Fiddler that will let you deeply inspect your network traffic.
Alternatively if you can't easily tweak the HTTP Headers, then set a far expires header, but ensure the path to the file changes whenever you make a code change. Options include:
adding a time() stamp (always changes (yeah!) but doesn't cache (boo))
add the version control # to the file URL (works great, but you need to manage the updates properly within your tooling)
something fancier that creates a generated "fake" path to the file that auto changes on any modification to the file... but also loads the URL as expected, and sets the cache to "forever" (max 365 days according to the HTTP specs)
You may try queries to force the browser to load fresh CSS when it loads. To do this
<link rel="stylesheet" type="text/css" href="css-file-name.css?v=1.1">
If you are comfortable with php you may try below code to force the browser to load most updated CSS to load. To do this
<link rel="stylesheet" type="text/css" href="http://example.com/style.css?d=<?php echo time(); ?>" />
This will ensure browsers always load fresh CSS with last modified time stamp.
Hope this help you.
In the head section of the sample html file from the html5boilerplate project, I notice this:
<link rel="stylesheet" href="css/style.css?v=2">
Note the v=2 request variables. I also notice that this is never done for javascript files.
What is the actual function of doing this ?
The ?v=2 might be to prevent reading from cache by the browser. It's used when loading dynamic content from a static file, like so:
changingListOfStuff.txt?randomUselessPropertyToTrickBrowser=123456789
This forces the browser to use this exact file, not a cached version of changingListOfStuff.txt previously downloaded and stored by the browser. Caching speeds up loading time, but might provide an older version of the file if it changes rapidly.
Read more about caching here: http://en.wikipedia.org/wiki/Web_cache
this is just telling the version of the url. This is done to make a fresh request to the server.In case of css as we know to achieve performance some headers are modified so that next time css is served by the browser history.But every time a css is modifed specifically in case of version releases. Browser should make new requests that would happen only when the url changes. So v=2 probaly means a new version is in and the url should freshly fetch the content from css.
This is called cache busting...you can read it here too
http://manikandanc.blogspot.com/2005/11/cache-busting-with-javascript.html
this will avoid client to get the version from browser. When you change the javascript or css , the end client who already visited your website may get javascript from his cache.
You can increment the version no whenever you deploy the files to the production , so that it will get the latest file
hi i have a little problem
i uploaded a new version of my website.
and some users complained that they see some page i changed very very wrong.
anyway after a refresh they see it fine.
i think its because my css file got cached by them on an earlier time...
why isnt the browser downloading the css file by himself on first load?..
he should know the css file changed dosnt he?
thanks in advance
#UpTheCreek's method will work fine. But you can save some trouble by just changing the call and not changing the filename.
screen.css?v=12
This will also force a reload but will only require you to change the call.
he should know the css file changed
dosnt he?
Not necessarily. If your css files have been sent from the server with a max-age directive and/or an expiring date far in the future, browser are instructed to not make conditional requests to your resource (see http://developer.yahoo.com/blogs/ydn/posts/2007/05/high_performanc_2/) so they consider the resource in cache still valid.
In this case in order to force a new request you may need to rename the file or append a random querystring like file.css?848372034 or, even better, a version note like file.css?v=1
If you install the web developer toolbar (for Firefox or IE) you can disable cache. I use this when developing websites. It saves you having to rename your CSS every time you make a minor edit.
If you're on Apache try adding this in your root .htaccess:
<FilesMatch ".(css|jpg|gif|ico|jpeg|png|html)$">
ExpiresActive On
Header set Expires "Mon, 22 Nov 2010 06:00:00 GMT"
</FilesMatch> [L]
Include only file types you don't want cached , eg:
<FilesMatch ".(css|js)$">
If you know when you want to change files, set a future date - your site will be faster if these files are not regularly refreshed.
If you don't set an expiry date, browsers cache these files in proportion to their age.