繁体   English   中英

如何清除或替换缓存的图像

[英]how to clear or replace a cached image

我知道有很多方法可以防止图像缓存(例如通过 META 标记),还有一些不错的技巧可以确保每次页面加载时都显示图像的当前版本(例如 image.jpg?x=timestamp ),但是有没有办法真正清除或替换浏览器缓存中的图像,以便上述方法都不是必需的?

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

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

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

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

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

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

要控制缓存,您可以在每次 URL 内容更改时更改 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 脚本提供图像(默认情况下它们具有糟糕的可缓存性;)

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

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

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

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

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

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

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

<script>
var num = Math.random();
var imgSrc= "image.png?v="+num;
$(function() {
$('#imgID').attr("src", imgSrc);
})
</script>

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

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

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

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

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

更改图像的 ETAG。

听起来您的问题的基础是如何从缓存中获取旧版本的图像。 我只是成功地进行了一次新调用并在标头中指定不要从缓存中提取。 一旦你获取它,你只是把它扔掉,但浏览器的缓存此时应该有更新的图像。

    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)

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

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

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

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

我找到了这篇关于如何缓存任何文件的文章

在本文中有很多方法可以强制清除缓存,但这是我为我的图像所做的方法:

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

请参阅http://en.wikipedia.org/wiki/URI_scheme

请注意,您可以提供唯一的 username:password@ 组合作为 uri 域部分的前缀。 在我的实验中,我发现将其与假 ID(或我假设的密码)包含在一起会导致将资源视为唯一的 - 从而根据需要破坏缓存。

只需使用时间戳作为用户名,据我所知,只要未打开身份验证,服务器就会忽略 uri 的这一部分。

顺便说一句 - 我也无法将上面的技巧与谷歌地图标记图标缓存问题一起使用,我在 ?param=timestamp 技巧起作用的地方遇到了问题,但导致了覆盖消失的问题。 永远无法弄清楚为什么会发生这种情况,但到目前为止使用这种方法效果很好。 我不确定的是,传递虚假凭据是否会对服务器性能产生任何不利影响。 如果有人知道我很想知道,因为我还没有进行大批量生产。

请报告您的结果。

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

当不能更改图像文件名时,请使用服务器端会话变量和 javascript window.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

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

希望这可以帮助。

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

你在运行 Firefox 对吗?

  • 找到Tools菜单
  • 选择Clear Private Data
  • 取消选中所有复选框,但确保选中Cache
  • 按确定

:-)

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

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

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

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

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

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

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

我怎么看这样做是:

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

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

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

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

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

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

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

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

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.'"/>   ';                  
}

尝试以下解决方案,

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

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

试试这个代码片段:

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

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

我通常和@Greg 告诉我们的一样,我有一个功能:

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

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

我希望它有帮助。

我尝试了一些非常简单的事情:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM