49

我知道有很多方法可以防止图像缓存(例如通过 META 标签),以及一些很好的技巧来确保每次页面加载时都会显示图像的当前版本(例如 image.jpg?x=timestamp ),但是有什么方法可以真正清除或替换浏览器缓存中的图像,这样上述两种方法都不是必需的吗?

例如,假设页面上有 100 张图像,这些图像被命名为“01.jpg”、“02.jpg”、“03.jpg”等。如果替换图像“42.jpg”,则为有什么办法可以在缓存中替换它,以便“42.jpg”在连续页面加载时自动显示新图像?我不能使用 META 标记方法,因为我需要 ISN"T 替换的所有内容以保持缓存,并且我不能使用时间戳方法,因为我不希望每次页面都重新加载所有图像负载。

我已经绞尽脑汁并在互联网上搜索了一种方法(最好是通过javascript),但没有运气。有什么建议么?

4

22 回答 22

62

如果您正在动态编写页面,则可以将上次修改的时间戳添加到 URL:

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

于 2008-11-26T19:28:40.520 回答
14

<meta>绝对无关紧要。事实上,您根本不应该尝试使用它来控制缓存(当任何东西读取文档内容时,它已经被缓存了)。

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

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

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

短期文件的随机 URL 是个坏主意。它会用无用的文件污染缓存,并强制尽快清除有用的文件。

如果您有 Apache,mod_headers然后使用适当的规则mod_expires创建文件。.htaccess

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

以上将使*-nocache.jpg文件不可缓存。

您还可以通过 PHP 脚本提供图像(默认情况下它们具有糟糕的缓存能力;)

于 2008-11-26T19:29:20.130 回答
13

与其他一些答案所说的相反,客户端javascript有一种方法可以替换缓存的图像诀窍是创建一个 hidden <iframe>,将其src属性设置为图像 URL,等待它加载,然后通过调用强制重新加载它location.reload(true)。这将更新图像的缓存副本。然后,您可以替换<img>页面上的元素(或重新加载页面)以查看图像的更新版本。

(小警告:如果更新单个<img>元素,并且如果有多个具有更新的图像,则必须全部清除或删除它们,然后替换或重置它们。如果您一个接一个地进行,一些浏览器会从其他标签复制图像的内存版本,结果是您可能看不到更新的图像,尽管它在缓存中)。

我在这里发布了一些代码来进行这种更新。

于 2014-03-15T22:17:29.917 回答
10

像这样更改图像 url,在查询字符串中添加一个随机字符串。

"image1.jpg?" + DateTime.Now.ToString("ddMMyyyyhhmmsstt");
于 2012-10-25T11:52:11.093 回答
7

我确信大多数浏览器都尊重Last-Modified HTTP 标头。将它们发送出去并请求新图像。如果 Last-Modified 行没有改变,它将被浏览器缓存。

于 2008-11-26T19:29:34.810 回答
5

您可以在图像上附加一个随机数,就像给它一个新版本一样。我已经实现了类似的逻辑,并且运行良好。

<script>
var num = Math.random();
var imgSrc= "image.png?v="+num;
$(function() {
$('#imgID').attr("src", imgSrc);
})
</script>
于 2015-11-24T15:34:42.150 回答
2

不,没有办法强制删除浏览器缓存中的文件,无论是通过网络服务器还是通过您可以放入它发送的文件中的任何内容。浏览器缓存归浏览器所有,由用户控制。

因此,您应该将每个文件和每个 URL 视为应谨慎管理的宝贵资源。

因此,porneL 对图像文件进行版本控制的建议似乎是最好的长期答案。ETAG在正常情况下使用,但也许你的努力已经无效了?按照建议尝试更改 ETAG。

于 2008-11-26T23:48:25.787 回答
2

使用 ?x=timestamp 技巧的原因是因为这是基于每个图像执行此操作的唯一方法。即动态生成图像名称并指向输出图像的应用程序。

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

于 2008-11-26T19:28:35.530 回答
2

我发现这篇关于如何缓存任何文件的文章

在这篇文章中有很多方法可以强制缓存破坏,但这是我为我的图像做的方式:

fetch('/thing/stuck/in/cache', {method:'POST', credentials:'include'});
于 2021-04-30T15:55:39.477 回答
1

See http://en.wikipedia.org/wiki/URI_scheme

Notice that you can provide a unique username:password@ combo as a prefix to the domain portion of the uri. In my experimentation, I've found that inclusion of this with a fake ID (or password I assume) results in the treatment of the resource as unique - thus breaking the caching as you desire.

Simply use a timestamp as the username and as far as I can tell the server ignores this portion of the uri as long as authentication is not turned on.

Btw - I also couldn't use the tricks above with a google map marker icon caching problem I was having where the ?param=timestamp trick worked, but caused issues with disappearing overlays. Never could figure out why this was happening, but so far so good using this method. What I'm unsure of, is if passing fake credentials will have any adverse server performance affects. If anyone knows I'd be interested to know as I'm not yet in high volume production.

Please report back your results.

于 2011-09-16T17:51:39.757 回答
1

更改图像的 ETAG。

于 2008-11-26T19:29:22.627 回答
1

这是使用 PHP 函数 filemtime() 的解决方案:

<?php 
     $addthis = filemtime('myimf.jpg');
?> 
<img src="myimg.jpg?"<?= $addthis;?> >

使用文件修改时间作为参数将导致它从缓存版本中读取,直到文件发生更改。这种方法比使用随机数更好,因为如果文件没有更改,缓存仍然可以工作。

于 2020-04-16T10:36:43.080 回答
1

听起来您的问题的基础是如何从缓存中获取旧版本的图像。我已经成功地进行了一个新的调用并在标头中指定不要从缓存中提取。获取后您只是将其丢弃,但浏览器的缓存此时应该具有更新的图像。

    var headers = new Headers()
    headers.append('pragma', 'no-cache')
    headers.append('cache-control', 'no-cache')

    var init = {
      method: 'GET',
      headers: headers,
      mode: 'no-cors',
      cache: 'no-cache',
    }

    fetch(new Request('path/to.file'), init)

但是,重要的是要认识到这只会影响调用它的浏览器。如果您希望在替换图像后为任何浏览器提供新版本的文件,则需要通过服务器配置来完成。

于 2019-11-27T21:37:51.587 回答
0

当更改图像文件名不是一个选项时,请使用服务器端会话变量和 javascriptwindow.location.reload()函数。如下:

上传完成后:

Session("reload") = "yes"

在 page_load 上:

If Session("reload") = "yes" Then
    Session("reload") = Nothing
    ClientScript.RegisterStartupScript(Me.GetType), "ReloadImages", "window.location.reload();", True)
End If

这允许客户端浏览器仅刷新一次,因为会话变量在一次发生后被重置。

希望这可以帮助。

于 2009-12-17T13:06:10.993 回答
0

如果重新上传图像,有没有办法清除或替换以前缓存的图像客户端?在我上面的例子中,目标是让浏览器忘记“42.jpg”是什么

你在运行Firefox对吗?

  • 查找Tools菜单
  • 选择Clear Private Data
  • 取消勾选除确保Cache已选中之外的所有复选框
  • 按确定

:-)

说真的,我从来没有听说过这样的东西存在,我怀疑是否有它的 API。我无法想象浏览器开发人员让你在他们的缓存中四处寻找是个好主意,而且我看不出他们有任何动机来实现这样的功能。

我不能使用 META 标记方法或时间戳方法,因为我希望在正常情况下缓存所有图像。

为什么不能使用时间戳(或 etag,相当于同一件事)?请记住,您应该使用图像文件本身的时间戳,而不仅仅是Time.Now.
我讨厌成为坏消息的传递者,但你别无选择。

如果图像没有改变,时间戳也不会改变,所以一切都会“在正常情况下”被缓存。如果图像确实发生了变化,他们将获得一个新的时间戳(出于缓存原因,他们需要这样做),但是该时间戳将永远保持有效,直到有人再次替换图像。

于 2008-11-26T20:14:42.813 回答
0

要替换 pictore 的缓存,您可以在服务器端存储一些版本值,当您加载图片时,只需发送此值而不是时间戳。当您的图像将更改时,请更改其版本。

于 2012-12-06T14:06:04.607 回答
0

经过大量测试,我通过以下方式找到了解决方案。

1-我创建一个临时文件夹来复制名称添加时间()的图像..(如果文件夹存在我删除内容)

2-从该临时本地文件夹加载图像

通过这种方式,我始终确保浏览器永远不会缓存图像并且 100% 正确工作。

if (!is_dir(getcwd(). 'articulostemp')){
    $oldmask = umask(0);mkdir(getcwd(). 'articulostemp', 0775);umask($oldmask);
}else{
    rrmfiles(getcwd(). 'articulostemp');
}   
foreach ($images as $image) { 
    $tmpname = time().'-'.$image;
    $srcimage = getcwd().'articulos/'.$image;
    $tmpimage = getcwd().'articulostemp/'.$tmpname;
    copy($srcimage,$tmpimage);
    $urlimage='articulostemp/'.$tmpname;
    echo '  <img loading="lazy" src="'.$urlimage.'"/>   ';                  
}
于 2020-12-28T07:50:16.797 回答
0

试试这个代码片段:

var url = imgUrl? + Math.random();

这将确保每个请求都是唯一的,因此您将始终获得最新的图像。

于 2016-10-03T11:40:12.487 回答
0

由于这里的大多数(如果不是全部)答案和评论都是问题部分的副本,或者足够接近,我将投入 2 美分。

我只想指出,即使有一种方法,也很难实施。它的逻辑使我们陷入困境。从一个逻辑的角度来看,告诉浏览器替换列表中每个更改图像的缓存图像,因为某个日期是理想的但是......你什么时候会删除列表,你怎么知道每个人都有最新版本谁会访问再次?

因此,正如 OP 所要求的,我的第一个“建议”是这个列表理论。

我如何看待这样做是:

A.) 有一个可以存储我们动态和手动更改的图像 url 的列表。

B.) 设置一个截止日期,在该日期将重置捕获并且无论如何都会截断列表。

C.0)通过 i 框架检查站点入口与浏览器的列表,该列表可以在后台运行,并设置较短的缓存标头,以根据列表中最远的日期或类似性质的方式重新缓存它们。

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

C.1a)这意味着我们的列表可能需要每个图像的更多信息,我认为很明显可能需要一些服务器端脚本来根据每个图像的要求调整标题,以最大程度地减少重新缓存更改站点的脚步图片。

我的第二个“建议”是通知用户更改并指导他们清除缓存。(小心,尽可能仅删除图像和文件,或警告他们由于该过程而删除数据)

PS这只是一个受过教育的想法。一个快速的理论。如果/当我成功时,我会发布决赛。可能不在这里,因为它需要服务器端脚本。这至少是 OP 的问题中没有提到的一个建议,他说他已经尝试过了。

于 2019-11-24T19:11:07.373 回答
-1

尝试以下解决方案,

myImg.src = " http://localhost/image.jpg ?" + 新日期().getTime();

以上解决方案对我有用:)

于 2016-09-14T12:24:00.037 回答
-1

我通常会像@Greg 告诉我们的那样做,我有一个功能:

function addMagicRefresh(url)
{
    var symbol = url.indexOf('?') == -1 ? '?' : '&';
    var magic = Math.random()*999999;
    return url + symbol + 'magic=' + magic;
}

这将起作用,因为您的服务器接受它并且您不以任何其他方式使用“魔术”参数。

我希望它有所帮助。

于 2017-01-27T15:55:10.797 回答
-2

我尝试了一些非常简单的方法:

转到网站的 FTP 文件夹并将 IMG 文件夹重命名为 IMG2。刷新您的网站,您将看到图像将丢失。然后将文件夹 IMG2 重命名回 IMG 就完成了,至少它在 Safari 中对我有用。

于 2014-10-20T19:37:11.077 回答