…say you’re using Javascript to reload an image periodically, say, every 60 seconds, and the image never refreshes. If you look for help across the web (as undoubtedly you have, since you’re here now, right?) you’ll find a) A bunch of people telling you to tag on a url param that’s a random number, and b) A bunch of snippy JS people who will insist, very condescendingly, you haven’t set your response headers correctly, and it’s not javascript’s problem, and you should think before you post such stupid questions.
Well, it turns out they’re both wrong. With the latter, the problem is, a browser has an internal page-level memory space that it will “remember” image urls with. When you create an image in javascript (via an Image() object or innerHTML, take your pick), if that image src has already been requested once on that page, the browser will give you that image from its internal memory, regardless of the image’s Expire or Cache-control headers. It won’t be put into the browser’s cache, sure, but it still stays in the browser’s memory for as long as you’re viewing that page.
The former seems to be the quick fix – the image src is always unique, so it’s not in memory, and the browser will ping the server for the image. But this approach fails if you’ve actually set your target image’s headers correctly (which of course you should). Because with this approach, the server sees each request as unique, and will send a new copy of the image down the pipe, regardless of if you wanted it to or not. You’re similarly screwed if you’re working on a high-traffic sites using a CDN – since a CDN (usually) contains cached copies of files from a master server, adding the cache-busting parameter to an image on a CDN will force the CDN to re-acquire the image from the master server before sending the image, which defeats the whole purpose of using a CDN in the first place.
The solution, unfortunately, is pretty hacky – to add a hash mark (#) to your image before applying a cache-busting parameter, i.e.:
function updateImage() { document.getElementById('image_arena').innerHTML = '<img src="/your/constantly/updating/image.jpg#e' + Math.random() + '">'; setTimeout(updateImage, 60000); return; }
This will psyche out the browser into thinking the URL of the image is unique (“Hey Firefox, look over there! PSYCHE!!11!”), but in the actual HTTP request anything beyond the hash gets stripped before the request is made. So, the browser thinks the request is unique and pings the server for it, but the server will know for reals wether or not the request is new, and send the appropriate 200/304 response*. Everyone’s happy, except for possibly your sense of aesthetics, since that is an ugly url you’re passing. But since you’re the only one who will probably see them, you’ll be alone in your secret shame.
*Yes, I did just bust some HTTP response codes.
Hello,
First of all, thanks for the very interesting post, you are the first I found which tackles this issue. Your solution is, by far, the closest to what I am looking for, as a) is not good for me, and b) is starting to annoy me 🙂
However, I would like a way for Firefox to only reload the image if it’s cache validity has expired, and your solution doesn’t allow this. At least, it doesn’t send the request up my CDN after reaching the first proxy, but do you think there would be a way for it never to even reach the first proxy if the Firefox cache still holds a valid image? (IE doesn’t seem to have this problem, only Firefox)
Thanks a lot,
Yannack
Link | December 18th, 2008 at 8:10 am
I suppose you could make an AJAX request, parse the response headers, store the image’s cache validity on your page, and use the cache-busting hack when you need to pull the image, but that seems to be a tremendous amount of work to save a couple extra HTTP requests.
Remember that when a server returns a 304 response code, it’s saying “This image has not changed since the last time you requested it, so use your cached copy” – I guess the trick is to make your CDN’s cache of the image refresh itself correctly after the cache you set expires.
HTH,
Chip
Link | December 19th, 2008 at 8:22 am
thank you for this very useful post – i was having the same problem.
Link | April 9th, 2009 at 3:22 pm