How to force a web browser NOT to cache images

后端 未结 17 628
太阳男子
太阳男子 2020-11-22 13:51

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

相关标签:
17条回答
  • 2020-11-22 14:35

    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).

    Change this, and you've fixed your problem. I use timestamps, as with the solutions proposed above: Image-<timestamp>.jpg

    Presumably, whatever problems you're avoiding by keeping the same filename for the image can be overcome, but you don't say what they are.

    0 讨论(0)
  • 2020-11-22 14:39

    Ideally, you should add a button/keybinding/menu to each webpage with an option to synchronize content.

    To do so, you would keep track of resources that may need to be synchronized, and either use xhr to probe the images with a dynamic querystring, or create an image at runtime with src using a dynamic querystring. Then use a broadcasting mechanism to notify all components of the webpages that are using the resource to update to use the resource with a dynamic querystring appended to its url.

    A naive example looks like this:

    Normally, the image is displayed and cached, but if the user pressed the button, an xhr request is sent to the resource with a time querystring appended to it; since the time can be assumed to be different on each press, it will make sure that the browser will bypass cache since it can't tell whether the resource is dynamically generated on the server side based on the query, or if it is a static resource that ignores query.

    The result is that you can avoid having all your users bombard you with resource requests all the time, but at the same time, allow a mechanism for users to update their resources if they suspect they are out of sync.

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="mobile-web-app-capable" content="yes" />        
        <title>Resource Synchronization Test</title>
        <script>
    function sync() {
        var xhr = new XMLHttpRequest;
        xhr.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {            
                var images = document.getElementsByClassName("depends-on-resource");
    
                for (var i = 0; i < images.length; ++i) {
                    var image = images[i];
                    if (image.getAttribute('data-resource-name') == 'resource.bmp') {
                        image.src = 'resource.bmp?i=' + new Date().getTime();                
                    }
                }
            }
        }
        xhr.open('GET', 'resource.bmp', true);
        xhr.send();
    }
        </script>
      </head>
      <body>
        <img class="depends-on-resource" data-resource-name="resource.bmp" src="resource.bmp"></img>
        <button onclick="sync()">sync</button>
      </body>
    </html>
    
    0 讨论(0)
  • 2020-11-22 14:42

    With the potential for badly behaved transparent proxies in between you and the client, the only way to totally guarantee that images will not be cached is to give them a unique uri, something like tagging a timestamp on as a query string or as part of the path.

    If that timestamp corresponds to the last update time of the image, then you can cache when you need to and serve the new image at just the right time.

    0 讨论(0)
  • 2020-11-22 14:45

    You may write a proxy script for serving images - that's a bit more of work though. Something likes this:

    HTML:

    <img src="image.php?img=imageFile.jpg&some-random-number-262376" />
    

    Script:

    // PHP
    if( isset( $_GET['img'] ) && is_file( IMG_PATH . $_GET['img'] ) ) {
    
      // read contents
      $f = open( IMG_PATH . $_GET['img'] );
      $img = $f.read();
      $f.close();
    
      // no-cache headers - complete set
      // these copied from [php.net/header][1], tested myself - works
      header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Some time in the past
      header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 
      header("Cache-Control: no-store, no-cache, must-revalidate"); 
      header("Cache-Control: post-check=0, pre-check=0", false); 
      header("Pragma: no-cache"); 
    
      // image related headers
      header('Accept-Ranges: bytes');
      header('Content-Length: '.strlen( $img )); // How many bytes we're going to send
      header('Content-Type: image/jpeg'); // or image/png etc
    
      // actual image
      echo $img;
      exit();
    }
    

    Actually either no-cache headers or random number at image src should be sufficient, but since we want to be bullet proof..

    0 讨论(0)
  • 2020-11-22 14:46

    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 :)

    0 讨论(0)
提交回复
热议问题