How to force a web browser NOT to cache images

239,953

Solution 1

Armin Ronacher has the correct idea. The problem is random strings can collide. I would use:

<img src="picture.jpg?1222259157.415" alt="">

Where "1222259157.415" is the current time on the server.
Generate time by Javascript with performance.now() or by Python with time.time()

Solution 2

Simple fix: Attach a random query string to the image:

<img src="foo.cgi?random=323527528432525.24234" alt="">

What the HTTP RFC says:

Cache-Control: no-cache

But that doesn't work that well :)

Solution 3

I use PHP's file modified time function, for example:

echo <img  src='Images/image.png?" . filemtime('Images/image.png') . "'  />";

If you change the image then the new image is used rather than the cached one, due to having a different modified timestamp.

Solution 4

I would use:

<img src="picture.jpg?20130910043254">

where "20130910043254" is the modification time of the file.

When uploading an image, its filename is not kept in the database. It is renamed as Image.jpg (to simply things out when using it). When replacing the existing image with a new one, the name doesn't change either. Just the content of the image file changes.

I think there are two types of simple solutions: 1) those which come to mind first (straightforward solutions, because they are easy to come up with), 2) those which you end up with after thinking things over (because they are easy to use). Apparently, you won't always benefit if you chose to think things over. But the second options is rather underestimated, I believe. Just think why php is so popular ;)

Solution 5

use Class="NO-CACHE"

sample html:

<div>
    <img class="NO-CACHE" src="images/img1.jpg" />
    <img class="NO-CACHE" src="images/imgLogo.jpg" />
</div>

jQuery:

    $(document).ready(function ()
    {           
        $('.NO-CACHE').attr('src',function () { return $(this).attr('src') + "?a=" + Math.random() });
    });

javascript:

var nods = document.getElementsByClassName('NO-CACHE');
for (var i = 0; i < nods.length; i++)
{
    nods[i].attributes['src'].value += "?a=" + Math.random();
}

Result: src="images/img1.jpg" => src="images/img1.jpg?a=0.08749723793963926"

Share:
239,953
Philibert Perusse
Author by

Philibert Perusse

Updated on July 08, 2022

Comments

  • Philibert Perusse
    Philibert Perusse almost 2 years

    Background

    I am writing and using a very simple CGI-based (Perl) content management tool for two pro-bono websites. It provides the website administrator with HTML forms for events where they fill the fields (date, place, title, description, links, etc.) and save it. On that form I allow the administrator to upload an image related to the event. On the HTML page displaying the form, I am also showing a preview of the picture uploaded (HTML img tag).

    The Problem

    The problem happens when the administrator wants to change the picture. He would just have to hit the "browse" button, pick a new picture and press ok. And this works fine.

    Once the image is uploaded, my back-end CGI handles the upload and reloads the form properly.

    The problem is that the image shown does not get refreshed. The old image is still shown, even though the database holds the right image. I have narrowed it down to the fact that the IMAGE IS CACHED in the web browser. If the administrator hits the RELOAD button in Firefox/Explorer/Safari, everything gets refreshed fine and the new image just appears.

    My Solution - Not Working

    I am trying to control the cache by writing a HTTP Expires instruction with a date very far in the past.

    Expires: Mon, 15 Sep 2003 1:00:00 GMT
    

    Remember that I am on the administrative side and I don't really care if the pages takes a little longer to load because they are always expired.

    But, this does not work either.

    Notes

    When uploading an image, its filename is not kept in the database. It is renamed as Image.jpg (to simply things out when using it). When replacing the existing image with a new one, the name doesn't change either. Just the content of the image file changes.

    The webserver is provided by the hosting service/ISP. It uses Apache.

    Question

    Is there a way to force the web browser to NOT cache things from this page, not even images?

    I am juggling with the option to actually "save the filename" with the database. This way, if the image is changed, the src of the IMG tag will also change. However, this requires a lot of changes throughout the site and I rather not do it if I have a better solution. Also, this will still not work if the new image uploaded has the same name (say the image is photoshopped a bit and re-uploaded).

    • Philibert Perusse
      Philibert Perusse about 5 years
      I think this question could be rework to remove all of the "now useless context" that I put in there a while back when I wrote it. I think the title is the right one, and the top answer as well. But the question has been written originally to provide a lot of room for many kind of answers and could not have expected such a simple solution. Therefore the question is a bit convoluted for people comming in there to get the answer.
  • Joel Coehoorn
    Joel Coehoorn over 15 years
    One important addition is that you can never force a browser to do anything. All you can do is make friendly suggestions. It's up to the browser and the user to actually follow those suggestions. A browser is free to ignore this, or a user could override the defaults.
  • Piskvor left the building
    Piskvor left the building over 15 years
    Yours is a good solution, except that Pragma is not a response header.
  • danjah
    danjah almost 13 years
    Just a thought, and far too late to come to the party here - but since you have control of the image changing, perhaps it would be better to rename the image as it is updated, instead of adding a query string. So: 1222259157.jpg for example, instead of picture.jpg?1222259157. That way it is updated and but re-cached upon revisit.
  • killebytes
    killebytes almost 13 years
    @epochwolf some servers doesnt allow adding text after the "?". It just return a "page cannot be found". Is there any workarounds?
  • Shivan Dragon
    Shivan Dragon over 12 years
    Thank you that worked fine. Broke my neck off trying to figure out why JQUery's Ajax $.get(...) would not show up the new resource (or even actually make the call) in IE (when in all other browsers it worked). Appended the milli time something like $.get('/rawData?action=getLeftThumbId&bigImageId='+bigImageI‌​d+"&forceRefresh="+n‌​ew Date().getTime()
  • Sam YC
    Sam YC almost 11 years
    hi I wonder will html meta 'cache-control' solve the problem?
  • Vasilis Lourdas
    Vasilis Lourdas almost 11 years
    Great tip. You have both the caching and the image re-sent to the client if its modified time changes (overwritten or changed).
  • Grizly
    Grizly almost 11 years
    @Piskvor: w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.32 seems to say otherwise.
  • Samuel
    Samuel about 10 years
    +1 I think it's a much better idea than other answers because using the las modification time, your server will not try to give the same image multiple times to the same browser when nothing have changed in the image. There is a little overhead to extract the last write time of the image each time there is a request but for a large image, it's better than having to returns the image each time and when the image change, the user will have the new one. Thank you for this nice little addition.
  • x-yuri
    x-yuri about 10 years
    Well, one might store modification time along with the path to image in database. So the overhead might be even less significant. On the other hand if these are images which are part of source code we are talking about, one might cache their modification times too. By generating a script with modification times of images (e.g. images.php). This script must be regenerated each commit and eliminates overhead of determining modification times of files.
  • Doin
    Doin about 10 years
    Rather than adding the server time, which will prevent caching altogether, why not add the file's last-modified time after the '?'. That way, the image will be cached normally until it next changes.
  • Doin
    Doin about 10 years
    Or, use the image's last-modified time, instead of a CRC, even better!
  • f.arcarese
    f.arcarese almost 10 years
    The last comment by Doin have to be upvoted! Smart caching is important indeed, why someone would have to download over and over the same file?
  • jtate
    jtate almost 10 years
    I agree, the comment by @Doin should be upvoted. No need to force the browser to fetch the image when you don't actually need to.
  • Patrick
    Patrick over 9 years
    -1 This will disable caching making this approach extremly ineffecient only suited for debbuging but not for any kind of production env.
  • cquezel
    cquezel over 7 years
    @for3st why downvote? this is exactly what the question asked: How to force a web browser NOT to cache images. Whether this is a good idea is another question.
  • oriadam
    oriadam about 7 years
    The filemtime solution is better also because md5 takes a lot of processing power.
  • Dmytro
    Dmytro over 5 years
    @for3st you should not downvote just because you don't like the question. Sometimes you MUST bypass cache; This is often true if you expect a resource to update very often and the resource is critical to the presentation. Sometimes you can't afford the client to get outdated resource. Ideally you only do this on request of the user(eg add a button to let user manually choose to force cache bypass) but sometimes this is more expensive when you need to send additional requests to check whether it is out of sync or not, and adding such a button is undesirable.
  • Dmytro
    Dmytro over 5 years
    Worth noting that implementing this solution puts stress on the server per request and won't necessarily work since the browser can cache the php page which contains the time generated at the time of initial request which gets cached. This would only work reliably if the page as well had a dynamic query string.
  • Patrick
    Patrick over 5 years
    @Dmitry You are kind of right, the questioner did ask the wrong question (more like, "How to handle this" instead of "How to create a specific hack"). IMHO the answer is to create immutable resources (ie. unqique URL that incorporates a hash of the data and unlimited caching time), this would be best of both worlds and is a http caching best practice. See here: developers.google.com/web/fundamentals/performance/… . However I still believe that this answer is a hack.
  • Dmytro
    Dmytro over 5 years
    @for3st i agree that it's kind of a hack since you shouldn't assume that the browser will not cache your resource even if the querystring varies; the browser should be assumed to be configurable enough to cache anyway, and if the resource is meant to by dynamic the resource url should be dynamic too. Sadly doing so is significantly more complicated than having dynamic querystrings, and in almost all cases it is safe to assume dynamic querystring will be treated as an entirely new resource and bypass caching, as many php/serverside resources and forms will stop behaving correctly otherwise.
  • Dmytro
    Dmytro over 5 years
    @for3st actually on second thought you can't really call it a hack, since querystring is a part of the url, and no browser can cache varying querystring resources since forms must behave correctly on anything that can be considered a general purpose browser. It's clever but it's not a hack. Its just ugly in that if you request "a?b=c", further requests for "a" may still use the outdated resource(even though the updated version is in cache as well), and I witnessed this firsthand in chrome.
  • Woody
    Woody over 5 years
    Spent days trying to get Chromium based app to stop caching images. The ?nocache with time echo solved the issue. Thank you!
  • Satish Patro
    Satish Patro almost 5 years
    how to give Cache-Control: no-cache in normal html <img> tag?
  • Satish Patro
    Satish Patro almost 5 years
    Does it need to be come in response header?
  • drooh
    drooh almost 5 years
    @x-yori this is why I am opting to store this updated field in the database rather than running filemtime stackoverflow.com/questions/56588850/…
  • drooh
    drooh almost 5 years
    see here for another option stackoverflow.com/questions/56588850/…
  • Ahi Tuna
    Ahi Tuna over 4 years
    Simple, elegant, and doesn't require server side rendering. NICE!
  • Khurram Shaikh
    Khurram Shaikh over 4 years
    This method I am using since 2012 and its effective. other headers wont work like they should. Even sometime CSS/Javacscript files get cached. same random string method work for this issue.
  • Khurram Shaikh
    Khurram Shaikh over 4 years
    Absolute nailed it. Great tip mate.
  • Rica Gurgel
    Rica Gurgel almost 4 years
    Perfect ! Just a extra tip: <img src="images/image.png?<?php echo filemtime('images/image.jpg')?>">
  • Quentin
    Quentin about 3 years
    What is the point of posting this answer? It is the same (even down to the function you are recommending be used to get the time) as the accepted answer from 13 years ago.
  • Manngo
    Manngo almost 3 years
    One reason you might want to disable image caching is to allow a reference to a dynamically generated image which updates periodically.
  • Alexandr
    Alexandr almost 3 years
    @Manngo, have you read my comment carefully?
  • Asanka
    Asanka over 2 years
    @RicaGurgel thanks for the above, I tried adding it to the php file as below to get the latest image from the server <img class="weather-cam-box alignleft" src="<?php echo '/cameraimages/webcam.jpg'.filemtime('/cameraimages/webcam.j‌​pg' ); ?>" alt="" width="100%" height="764" /> it doesnt work for somereason,