如何强制Web浏览器不缓存图像

Phi*_*sse 115 html caching image image-caching browser-cache

背景

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

问题

当管理员想要更改图片时,会发生此问题.他只需点击"浏览"按钮,选择一张新照片然后按确定即可.这很好用.

上传图像后,我的后端CGI处理上传并正确地重新加载表单.

问题是显示的图像没有刷新.即使数据库保存正确的图像,仍会显示旧图像.我已将其缩小到图像在Web浏览器中缓存的事实.如果管理员点击Firefox /资源管理器/ Safari中的RELOAD按钮,则所有内容都会刷新,并且只会显示新图像.

我的解决方案 - 不工作

我试图通过写一个过去很远的日期的HTTP Expires指令来控制缓存.

Expires: Mon, 15 Sep 2003 1:00:00 GMT
Run Code Online (Sandbox Code Playgroud)

请记住,我在管理方面,我并不关心页面是否需要更长时间才能加载,因为它们总是过期.

但是,这也不起作用.

笔记

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

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

有没有办法强制Web浏览器不缓存此页面中的内容,甚至图像?

我正在使用数据库实际"保存文件名"的选项.这样,如果图像被更改,IMG标签的src也将改变.但是,这需要在整个站点进行大量更改,如果我有更好的解决方案,我宁愿不这样做.此外,如果上传的新图像具有相同的名称(例如图像有点照片并重新上传),这仍然无效.

epo*_*olf 174

Armin Ronacher有正确的想法.问题是随机字符串可能会发生冲突.我会用:

<img src="picture.jpg?1222259157.415" alt="">
Run Code Online (Sandbox Code Playgroud)

其中"1222259157.415"是服务器上的当前时间.(注意:我使用python的time.time()来生成)

  • 而不是添加服务器时间(这将完全阻止缓存),为什么不在'?'之后添加文件的最后修改时间.这样,图像将被正常缓存,直到下一次更改. (42认同)
  • 一个重要的补充是,你永远不能_force_浏览器做任何事情.你所能做的就是提出友好的建议.这取决于浏览器和用户实际遵循这些建议.浏览器可以忽略这一点,或者用户可以覆盖默认值. (31认同)
  • 乔尔,你最好在你自己的答案中补充一点. (8认同)
  • Doin的最后评论必须得到投票!智能缓存确实很重要,为什么有人必须一遍又一遍地下载同一个文件? (3认同)
  • 只是一个想法,来这里参加聚会为时已晚 - 但由于您可以控制图像更改,也许最好在更新时重命名图像,而不是添加查询字符串。所以:例如:1222259157.jpg,而不是picture.jpg?1222259157。这样它会被更新,但会在重新访问时重新缓存。 (2认同)
  • @Danjah,用静态文件管理会很烦人. (2认同)
  • @for3st 为什么要投反对票?这正是问题所在:如何强制网络浏览器不缓存图像。这是否是一个好主意是另一个问题。 (2认同)
  • @for3st,你不应该仅仅因为你不喜欢这个问题就投反对票。有时你必须绕过缓存;如果您希望资源经常更新并且该资源对于演示至关重要,则通常会出现这种情况。有时您无法让客户获得过时的资源。理想情况下,您仅根据用户的请求执行此操作(例如添加一个按钮以让用户手动选择强制绕过缓存),但有时当您需要发送额外的请求来检查它是否不同步时,这会更昂贵,并且添加这样的按钮是不可取的。 (2认同)

Arm*_*her 45

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

<img src="foo.cgi?random=323527528432525.24234" alt="">
Run Code Online (Sandbox Code Playgroud)

HTTP RFC说的是什么:

Cache-Control: no-cache
Run Code Online (Sandbox Code Playgroud)

但那不是很好:)

  • 如何在普通的 html &lt;img&gt; 标签中提供 Cache-Control: no-cache ? (2认同)

小智 18

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

echo <img  src='Images/image.png?" . filemtime('Images/image.png') . "'  />";
Run Code Online (Sandbox Code Playgroud)

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


x-y*_*uri 15

我会用:

<img src="picture.jpg?20130910043254">
Run Code Online (Sandbox Code Playgroud)

其中"20130910043254"是文件的修改时间.

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

我认为有两种类型的简单解决方案:1)首先想到的解决方案(直截了当的解决方案,因为它们很容易想出来),2)你在思考之后最终得到的解决方案(因为它们很容易使用).显然,如果你选择考虑事情,你不会总是受益.但我相信,第二种选择被低估了.试想为什么php如此受欢迎;)


小智 7

您可以编写一个代理脚本来提供图像 - 虽然这有点多了.有点喜欢这个:

HTML:

<img src="image.php?img=imageFile.jpg&some-random-number-262376" />
Run Code Online (Sandbox Code Playgroud)

脚本:

// 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();
}
Run Code Online (Sandbox Code Playgroud)

实际上,图像src上的无缓存标头或随机数应该足够了,但是因为我们想要防弹..


小智 7

使用Class =“ NO-CACHE”

范例html:

<div>
    <img class="NO-CACHE" src="images/img1.jpg" />
    <img class="NO-CACHE" src="images/imgLogo.jpg" />
</div>
Run Code Online (Sandbox Code Playgroud)

jQuery的:

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

javascript:

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

结果:src =“ images / img1.jpg” => src =“ images / img1.jpg?a = 0.08749723793963926”


小智 6

我是一个新的编码器,但这是我想出来的,阻止浏览器缓存并保持我的网络摄像头视图:

<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">
Run Code Online (Sandbox Code Playgroud)

不知道什么在什么浏览器上工作,但它确实适用于某些人:IE:当网页刷新和网站重新访问时(无需刷新).CHROME:仅在刷新网页时才有效(即使在重新访问后).SAFARI和iPad:不起作用,我必须清除历史和Web数据.

关于SAFARI/iPad的任何想法?


Tar*_*rik 5

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

<img src="image.png?cache=none">
Run Code Online (Sandbox Code Playgroud)

首先。

但是,如果您添加cache=none参数(这是静态的“无”字),则不会产生任何影响,浏览器仍会从缓存中加载。

这个问题的解决方法是:

<img src="image.png?nocache=<?php echo time(); ?>">
Run Code Online (Sandbox Code Playgroud)

您基本上添加了 unix 时间戳以使参数动态且没有缓存,它起作用了。

但是,我的问题有点不同:我正在加载动态生成的 php 图表图像,并使用 $_GET 参数控制页面。我希望在 URL GET 参数保持不变时从缓存中读取图像,并且在 GET 参数更改时不缓存。

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

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

编辑

虽然上述解决方案工作得很好,但有时您希望提供缓存版本,直到文件被更改。(使用上述解决方案,它会完全禁用该图像的缓存)因此,要从浏览器提供缓存图像,直到图像文件使用发生变化:

echo "<img src='/images/mychart.png?hash=" . filemtime('mychart.png') . "'>";
Run Code Online (Sandbox Code Playgroud)

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

  • `filemtime` 解决方案更好,因为 `md5` 需要大量的处理能力。 (2认同)
  • 花了几天时间试图让基于 Chromium 的应用程序停止缓存图像。?nocache with time echo 解决了这个问题。谢谢! (2认同)