如何清除或替换缓存图片。

53

我知道有很多方法可以防止图像缓存(比如通过标签),也有一些不错的技巧可以确保每次页面加载时显示当前版本的图像(比如image.jpg?x=timestamp),但是是否有任何方式可以清除或替换浏览器缓存中的图像,以使上述两种方法都不再必要?

例如,假设页面上有100个图像,这些图像的名称为“01.jpg”、“02.jpg”、“03.jpg”等。如果替换了图像“42.jpg”,是否有任何方法可以在缓存中替换它,以便“42.jpg”会自动在后续页面加载时显示新图像?我不能使用标签方法,因为我需要保留所有未替换的内容,我也不能使用时间戳方法,因为我不想在每次页面加载时重新加载所有图像。

我已经费尽心思,在互联网上搜寻可行的方法(最好通过JavaScript实现),但没有成功。有什么建议吗?


请使用以下链接:https://dev59.com/ZHVC5IYBdhLWcg3w-mZO#70954519 - Ravi Singh
22个回答

66
如果你正在动态编写网页,你可以将最后修改时间戳添加到URL中:

<img src="image.jpg?lastmod=12345678" ...


2
我认为这是最好的答案,因为它仍然允许浏览器缓存。 - Michael St Clair
5
<img src="image.jpg?<?php echo filemtime('image.jpg') ?>">翻译为:这样写更有动态效果! - luke_mclachlan
在 PHP 中,通常我们可以像这样使用 rand 函数:<img src="image.jpg?new=<?php rand() ?>">。 - nafischonchol

15

<meta> 标签是完全无关的。实际上,您不应该尝试使用它来控制缓存(当任何内容读取文档内容时,它已经被缓存了)。

在 HTTP 中,每个 URL 都是独立的。无论您对 HTML 文档做什么,都不会应用于图像。

要控制缓存,您可以在每次内容更改时更改 URL。 如果您定期更新图片,请允许它们永久缓存并使用新文件名(带有版本、哈希或日期)用于新图片 - 这是长时间存活文件的最佳解决方案。

如果您的图片非常频繁更改(每隔几分钟甚至每次请求),则发送 Cache-control: no-cacheCache-control: max-age=xx,其中 xx 是图片“新鲜”的秒数。

对于短时间存在的文件,随机 URL 是一个糟糕的主意。它会使缓存中充满无用的文件,并迫使有用的文件更快地被清除。

如果您有 Apache 和 mod_headersmod_expires,那么创建具有适当规则的 .htaccess 文件。

<Files ~ "-nocache\.jpg">
   Header set Cache-control "no-cache"
</Files>

以上操作将使*-nocache.jpg文件无法被缓存。

你还可以通过PHP脚本提供图像服务(它们默认的缓存性能很差)。


12
与其他答案所说的相反,客户端JavaScript确实有一种方法可以替换缓存的图像。技巧是创建一个隐藏的<iframe>,将其src属性设置为图像URL,等待其加载,然后通过调用location.reload(true)强制重新加载它。这将更新图像的缓存副本。然后,您可以替换页面上的<img>元素(或重新加载页面)以查看图像的更新版本。 (小提示:如果更新单个<img>元素,并且如果有多个具有已更新图像的元素,则必须全部清除或删除它们,然后替换或重置它们。如果逐个执行此操作,则某些浏览器将从其他标签中复制图像的内存版本,结果可能是您可能看不到已更新的图像,尽管它在缓存中)。我在这里发布了一些代码来执行此类更新。

与许多网络文档所说的相反,location.reload() 没有参数。因此,无法通过此方法强制重新加载缓存。在MDN上了解更多信息。 - davidhartman00
这不是任何规范的一部分,但它被Firefox和IE都支持。 Firefox仍然支持它,如果您正在使用Firefox,则确实可以通过此方法强制重新加载缓存。 但是,对于其他现代浏览器,您无法这样做。 - Doin

10

将图像URL更改为这样,向查询字符串添加随机字符串。

"image1.jpg?" + DateTime.Now.ToString("ddMMyyyyhhmmsstt");

11
这实际上并没有刷新图像缓存,它只是欺骗浏览器认为这是一张新图像。使用这种方法,如果我检查Chrome缓存,我可以看到12个以上相同的图像。在服务器响应中设置Cache-Control对我来说是更好的解决方案,更少的是hack。理想情况下,您希望浏览器缓存图像,只是在更改时刷新它。 - Lex

7

我相信大多数浏览器都会遵循Last-Modified HTTP头。发送这些头信息并请求新的图片。如果Last-Modified行没有改变,它将被浏览器缓存。


5
您可以将一个随机数字附加到图片上,就像给它赋予一个新版本号一样。我已经实现了类似的逻辑,并且它正在完美地工作。
<script>
var num = Math.random();
var imgSrc= "image.png?v="+num;
$(function() {
$('#imgID').attr("src", imgSrc);
})
</script>

3

我在这篇文章中找到了如何清除任意文件缓存的方法。

虽然本文提供了多种强制清除缓存的方法,但这是我用于我的图像的方式:

fetch('/thing/stuck/in/cache', {method:'POST', credentials:'include'});

这种方法非常优雅且有效!最好的事情是它不会创建另一个图像(例如使用时间戳等)。如果您想在不重新加载页面的情况下更新图像,则必须将 src 设置为其他内容(例如空白图像、小型 base64 透明 gif 等),然后在调用 fetch 后将图像 src 设置回原始路径。 - lepe

2

使用 ?x=timestamp 技巧的原因是这是唯一可以在每个图像上执行的方法。或者动态生成图像名称并指向输出图像的应用程序。

我建议您在服务器端确定图像是否已更改/更新,如果是,则使用 ?x=timestamp 技巧输出您的 标记以强制显示新图像。


2
没有办法强制删除浏览器缓存中的文件,无论是通过Web服务器还是通过您发送的文件。浏览器缓存归浏览器所有,并由用户控制。因此,您应该将每个文件和每个URL视为珍贵资源,需要仔细管理。因此,porneL建议对图像文件进行版本控制似乎是最好的长期解决方案。ETAG在正常情况下被使用,但是也许您的努力已经使其失效了?请尝试更改ETAG,如建议所述。

1
由于这里大部分(如果不是全部)的答案和评论都是问题的一部分或相似,因此我将加入我的两分钱。我只想指出,即使有方法,实现起来也会很困难。它的逻辑束缚了我们。从逻辑的角度来看,告诉浏览器为列表中的每个更改的图像替换其缓存的图像是理想的,但是...你何时将列表拆下来?你如何知道每个人是否都有最新的版本,谁会再次访问?因此,作为OP要求的第一个“建议”,我提出了这个列表理论。我如何看待这个问题:A.)有一个动态和手动更改的图像URL可以存储的列表。B.)设定一个死期,在此日期之后,缓存将被重置,并且列表将被截断。C.0)在站点入口处与浏览器通过i frame检查列表,可以在后台运行,设置较短的缓存标头以重新缓存所有内容,针对列表上最远的日期或类似的东西。

C.1) 使用 iframe 或 ajax/xhr 请求,您可以循环遍历列表中的每个图像,刷新页面以显示不同的图像,并根据其自身修改日期检查缓存。因此,在此图像的 onload 中使用服务器端来解密,如果它不是最后一个加载的图像,则转到下一个图像。

C.1a) 这意味着我们的列表可能需要更多关于每个图像的信息,我认为明显的一个是可能需要一些服务器端脚本来根据每个图像调整标头,以最小化重新缓存已更改的站点图像的步骤。

我的第二个“建议”是通知用户变更并引导他们清除缓存。(谨慎地在可能的情况下仅删除图像和文件,或者警告他们由于该过程而删除数据)

P.S. 这只是一种受过教育的构思。一个快速的理论。如果/当我制作出来,我会发布最终版本。可能不是在这里,因为它需要服务器端脚本。至少这是一个未在 OP 的问题中提到的建议,他说他已经尝试过。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接