English 中文(简体)
如何强制web浏览器不缓存图像
原标题:
  • 时间:2008-09-24 12:19:18
  •  标签:

Background

我正在为两个公益网站编写并使用一个非常简单的基于CGI的(Perl)内容管理工具。它为网站管理员提供了事件的HTML表单,他们填写字段(日期、地点、标题、描述、链接等)并保存。在该表单上,我允许管理员上传与事件相关的图像。在显示表单的HTML页面上,我还显示了上传图片的预览(HTML img标记)。

The Problem

当管理员想要更改图片时,就会出现此问题。他只需要点击“浏览”按钮,选择一张新照片,然后按“确定”。这很好。

一旦上传了图像,我的后端CGI就会处理上传并正确地重新加载表单。

问题是显示的图像无法刷新。尽管数据库中有正确的图像,但旧图像仍然显示。我已经把它缩小到图像被缓存在网络浏览器中的事实。如果管理员在Firefox/Explorer/Safari中点击RELOAD按钮,所有内容都会被刷新,新图像就会出现。

My Solution - Not Working

我正试图通过编写一条日期在很久以前的HTTPExpires指令来控制缓存。

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

请记住,我是管理人员,我真的不在乎页面加载是否需要更长的时间,因为它们总是过期的。

但是,这也不起作用。

Notes

上传图像时,其文件名不会保存在数据库中。它被重命名为Image.jpg(在使用时简单地说明一下)。将现有图像替换为新图像时,名称也不会更改。只是图像文件的内容发生了更改。

网络服务器由托管服务/ISP提供。它使用Apache。

Question

有没有办法强制网络浏览器不缓存这个页面上的内容,甚至不缓存图像?

我正在处理与数据库一起实际“保存文件名”的选项。这样,如果图像发生更改,IMG标签的src也会发生更改。然而,这需要在整个网站上做很多更改,如果我有更好的解决方案,我宁愿不这样做。此外,如果上传的新图像具有相同的名称(比如图像经过PS处理后重新上传),这仍然不起作用。

最佳回答

阿明·罗纳彻的想法是正确的。问题是随机字符串可能会发生冲突。我会使用:

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

问题回答

简单修复:将随机查询字符串附加到图像:

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

HTTP RFC所说的:

Cache-Control: no-cache

但效果并不好:)

我使用PHP的文件修改时间函数,例如:

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

如果更改图像,则会使用新图像,而不是缓存的图像,因为修改后的时间戳不同。

我会使用:

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

其中“201300910043254”是文件的修改时间。

上传图像时,其文件名不会保存在数据库中。它被重命名为Image.jpg(只是为了在使用它时解决问题)。将现有图像替换为新图像时,名称也不会更改。只是图像文件的内容发生了更改。

我认为有两种类型的简单解决方案:1)首先想到的解决方案(简单的解决方案,因为它们很容易想出),2)经过深思熟虑后得出的解决方案。显然,如果你选择仔细考虑,你不会一直受益。但我认为,第二种选择被低估了。想想为什么<code>php</code>如此受欢迎;)

使用Class=“NO-CACHE”

示例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"

您可以编写一个代理脚本来提供图像——不过这需要更多的工作。像这样的东西:

HTML格式:

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

脚本:

// 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();
}

事实上,在image src中没有缓存头或随机数就足够了,但由于我们希望是防弹的。。

我在网上查了所有的答案,最好的答案似乎是:(实际上不是)

<img src="image.png?cache=none">

一开始

然而,如果添加<strong>cache=none</strong>参数(这是静态的“none”字),它不会产生任何影响,浏览器仍然从缓存加载。

这个问题的解决方案是:

<img src="image.png?nocache=<?php echo time(); ?>">

在基本上添加unix时间戳以使参数动态且无缓存的情况下,它起到了作用。

However, my problem was a little different: I was loading on the fly generated php chart image, and controlling the page with $_GET parameters. I wanted the image to be read from cache when the URL GET parameter stays the same, and do not cache when the GET parameters change.

为了解决这个问题,我需要散列$_GET,但由于它是数组,所以这里是解决方案:

$chart_hash = md5(implode( - , $_GET));
echo "<img src= /images/mychart.png?hash=$chart_hash >";

编辑

Although the above solution works just fine, sometimes you want to serve the cached version UNTIL the file is changed. (with the above solution, it disables the cache for that image completely) So, to serve cached image from browser UNTIL there is a change in the image file use:

echo "<img src= /images/mychart.png?hash=" . filemtime( mychart.png ) . " >";

filemtime()获取文件修改时间。

我是一个新的程序员,但以下是我的想法,以阻止浏览器缓存和保留我的网络摄像头视图:

<meta Http-Equiv="Cache" content="no-cache">
<meta Http-Equiv="Pragma-Control" content="no-cache">
<meta Http-Equiv="Cache-directive" Content="no-cache">
<meta Http-Equiv="Pragma-directive" Content="no-cache">
<meta Http-Equiv="Cache-Control" Content="no-cache">
<meta Http-Equiv="Pragma" Content="no-cache">
<meta Http-Equiv="Expires" Content="0">
<meta Http-Equiv="Pragma-directive: no-cache">
<meta Http-Equiv="Cache-directive: no-cache">

Not sure what works on what Browser, but it does work for some: IE: Works when webpage is refreshed and when website is revisited (without a refresh). CHROME: Works only when webpage is refreshed (even after a revisit). SAFARI and iPad: Doesn t work, I have to clear the History & Web Data.

对SAFARI/iPad有什么想法吗?

上传图像时,其文件名不会保存在数据库中。它被重命名为Image.jpg(只是为了在使用它时解决问题)。

改变这个,你就解决了你的问题。我使用时间戳,就像上面提出的解决方案一样:图像-<;时间戳>;。jpg格式

据推测,通过为图像保留相同的文件名来避免任何问题都是可以克服的,但你不知道它们是什么。

您必须使用唯一的文件名。这样地

<img src="cars.png?1287361287" alt="">

But this technique means high server usage and bandwidth wastage. Instead, you should use the version number or date. Example:

<img src="cars.png?2020-02-18" alt="">

但您希望它永远不会提供缓存中的图像。为此,如果页面不使用页面缓存,则可以使用PHP或服务器端。

<img src="cars.png?<?php echo time();?>" alt="">

However, it is still not effective. Reason: Browser cache ... The last but most effective method is Native JAVASCRIPT. This simple code finds all images with a "NO-CACHE" class and makes the images almost unique. Put this between script tags.

var items = document.querySelectorAll("img.NO-CACHE");
for (var i = items.length; i--;) {
    var img = items[i];
    img.src = img.src +  ?  + Date.now();
}

用法

<img class="NO-CACHE" src="https://upload.wikimedia.org/wikipedia/commons/6/6a/JavaScript-logo.png" alt="">

结果如下

https://example.com/image.png?1582018163634

您的问题是,尽管有Expires:标头,但您的浏览器正在重新使用更新前图像的内存副本,而不是检查其缓存。

我在类似商店的网站的管理后台上传产品图像时也遇到过类似的情况,在我的情况下,我决定最好的选择是使用javascript强制刷新图像,而不使用其他人已经在这里提到的任何URL修改技术。相反,我将图像URL放入一个隐藏的IFRAME中,在IFRAME的窗口上称为location.reload(true),然后替换页面上的图像。这将强制刷新图像,不仅是在我所在的页面上,而且在我访问的任何后续页面上,而客户端或服务器都不必记住任何URL查询字符串或片段标识符参数。

我在回答中发布了一些代码来实现这一点此处

从我的角度来看,禁用图像缓存是个坏主意。完全

这里的根本问题是——当图像在服务器端更新时,如何强制浏览器更新图像。

同样,从我个人的角度来看,最好的解决方案是禁用对图像的直接访问。而是通过服务器端过滤器/servlet/其他类似的工具/服务访问图像。

在我的情况下,这是一个rest服务,它返回图像并附加ETag作为响应。该服务保留所有文件的哈希,如果文件发生更改,则会更新哈希。它在所有现代浏览器中都能完美工作。是的,实施它需要时间,但这是值得的。

唯一的例外是收藏夹。由于某些原因,它不起作用。我无法强制浏览器从服务器端更新其缓存。ETag、Cache Control、Expires、Pragma标头,没有任何帮助。

在这种情况下,在url中添加一些随机/版本参数似乎是唯一的解决方案。

添加时间戳<;img src=“picture.jpg?t=<;?php echo time();?>;”>

总是在文件末尾给它一个随机数,并停止缓存

由于您和客户端之间可能存在行为不端的透明代理,完全保证图像不会被缓存的唯一方法是给它们一个唯一的uri,比如将时间戳标记为查询字符串或路径的一部分。

如果该时间戳对应于图像的最后更新时间,那么您可以在需要时缓存,并在适当的时间提供新图像。

我认为最初的问题是关于存储了一些文本信息的图像。因此,如果您在生成src=时可以访问文本上下文。。。url,考虑存储/使用图像字节的CRC32,而不是无意义的随机或时间戳。然后,如果显示有大量图像的页面,则只会重新加载更新后的图像。最终,如果CRC存储是不可能的,那么可以在运行时计算它并将其附加到url。

理想情况下,您应该为每个网页添加一个按钮/键绑定/菜单,并提供同步内容的选项。

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.

一个天真的例子是这样的:

通常情况下,图像会被显示和缓存,但如果用户按下按钮,则会向资源发送一个xhr请求,并在其后面附加一个时间查询字符串;由于可以假设每次按下的时间不同,它将确保浏览器绕过缓存,因为它无法判断资源是基于查询在服务器端动态生成的,还是忽略查询的静态资源。

结果是,您可以避免所有用户一直用资源请求轰炸您,但同时,允许用户在怀疑资源不同步时更新资源。

<!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>

I ve found Chrome specifically tries to get clever with the URL arguments solution on images. That method to avoid cache only works some of the time. The most reliable solution I ve found is to add both a URL argument (E.g. time stamp or file version) AND also change the capitalisation of the image file extension in the URL.

<img src="picture.jpg">

成为

<img src="picture.JPG?t=current_time">

所有答案都是有效的,因为它运行良好。但这样一来,浏览器每次加载带有不同URL的图像时,也会在缓存中创建另一个文件。因此,不要通过添加一些查询参数来更改URL。

因此,我们可以使用<code>缓存来更新浏览器缓存。put</code>

caches.open( YOUR_CACHE_NAME ).then(cache => {
  const url =  URL_OF_IMAGE_TO_UPDATE 
  fetch(url).then(res => {
    cache.put(url, res.clone())
  })
})

<code>cache.put</code>使用新的响应更新缓存。

更多信息:https://developer.mozilla.org/en-US/docs/Web/API/Cache/put

我制作了一个PHP脚本,可以自动在所有图像和链接上附加时间戳。您只需要将此脚本包含在页面中即可。享受

http://alv90.altervista.org/how-to-force-the-browser-not-to-cache-images/

Best solution is to provide current time at the end of the source href like <img src="www.abc.com/123.png?t=current_time">

this will remove the chances of referencing the already cache image. To get the recent time one can use performance.now() function in jQuery or javascript.





相关问题