简体   繁体   English

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

[英]How to force a web browser NOT to cache images

Background背景

I am writing and using a very simple CGI-based (Perl) content management tool for two pro-bono websites.我正在为两个公益网站编写和使用一个非常简单的基于 CGI (Perl) 的内容管理工具。 It provides the website administrator with HTML forms for events where they fill the fields (date, place, title, description, links, etc.) and save it.它为网站管理员提供了用于填写字段(日期、地点、标题、描述、链接等)并保存的事件的 HTML 表单。 On that form I allow the administrator to upload an image related to the event.在该表单上,我允许管理员上传与该事件相关的图像。 On the HTML page displaying the form, I am also showing a preview of the picture uploaded (HTML img tag).在显示表单的 HTML 页面上,我还显示了上传图片的预览(HTML img 标记)。

The Problem问题

The problem happens when the administrator wants to change the picture.当管理员想要更改图片时,就会出现问题。 He would just have to hit the "browse" button, pick a new picture and press ok.他只需点击“浏览”按钮,选择一张新图片,然后按确定。 And this works fine.这很好用。

Once the image is uploaded, my back-end CGI handles the upload and reloads the form properly.上传图片后,我的后端 CGI 会处理上传并正确重新加载表单。

The problem is that the image shown does not get refreshed.问题是显示的图像没有刷新。 The old image is still shown, even though the database holds the right image.即使数据库拥有正确的图像,旧图像仍会显示。 I have narrowed it down to the fact that the IMAGE IS CACHED in the web browser.我已将其范围缩小到图像被缓存在网络浏览器中的事实。 If the administrator hits the RELOAD button in Firefox/Explorer/Safari, everything gets refreshed fine and the new image just appears.如果管理员在 Firefox/Explorer/Safari 中点击 RELOAD 按钮,一切都会正常刷新,新图像就会出现。

My Solution - Not Working我的解决方案 - 不工作

I am trying to control the cache by writing a HTTP Expires instruction with a date very far in the past.我试图通过编写一个日期很远的 HTTP Expires 指令来控制缓存。

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

Remember that I am on the administrative side and I don't really care if the pages takes a little longer to load because they are always expired.请记住,我在管理方面,我并不关心页面是否需要更长的时间来加载,因为它们总是过期的。

But, this does not work either.但是,这也不起作用。

Notes笔记

When uploading an image, its filename is not kept in the database.上传图像时,其文件名不会保存在数据库中。 It is renamed as Image.jpg (to simply things out when using it).它被重命名为Image.jpg (在使用它时简单地说明一下)。 When replacing the existing image with a new one, the name doesn't change either.用新图像替换现有图像时,名称也不会改变。 Just the content of the image file changes.只是图像文件的内容发生了变化。

The webserver is provided by the hosting service/ISP.网络服务器由托管服务/ISP 提供。 It uses Apache.它使用 Apache。

Question问题

Is there a way to force the web browser to NOT cache things from this page, not even images?有没有办法强制网络浏览器不缓存此页面的内容,甚至不缓存图像?

I am juggling with the option to actually "save the filename" with the database.我正在处理使用数据库实际“保存文件名”的选项。 This way, if the image is changed, the src of the IMG tag will also change.这样,如果图片改变了,IMG标签的src也会改变。 However, this requires a lot of changes throughout the site and I rather not do it if I have a better solution.但是,这需要整个站点进行大量更改,如果我有更好的解决方案,我宁愿不这样做。 Also, this will still not work if the new image uploaded has the same name (say the image is photoshopped a bit and re-uploaded).此外,如果上传的新图像具有相同的名称,这仍然不起作用(例如图像经过了一些照片处理并重新上传)。

Armin Ronacher has the correct idea. Armin Ronacher 的想法是正确的。 The problem is random strings can collide.问题是随机字符串可能会发生冲突。 I would use:我会使用:

<img src="picture.jpg?1222259157.415" alt="">

Where "1222259157.415" is the current time on the server.其中“1222259157.415”是服务器上的当前时间。
Generate time by Javascript with performance.now() or by Python with time.time()通过 Javascript 使用performance.now()或 Python 使用time.time()生成时间

Simple fix: Attach a random query string to the image:简单修复:将随机查询字符串附加到图像:

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

What the HTTP RFC says: HTTP RFC 所说的:

Cache-Control: no-cache

But that doesn't work that well :)但这并没有那么好:)

I use PHP's file modified time function , for example:我使用PHP的文件修改时间函数,例如:

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

If you change the image then the new image is used rather than the cached one, due to having a different modified timestamp.如果您更改图像,则使用新图像而不是缓存的图像,因为具有不同的修改时间戳。

I would use:我会使用:

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

where "20130910043254" is the modification time of the file.其中“20130910043254”是文件的修改时间。

When uploading an image, its filename is not kept in the database.上传图像时,其文件名不会保存在数据库中。 It is renamed as Image.jpg (to simply things out when using it).它被重命名为 Image.jpg(在使用它时简单地说明一下)。 When replacing the existing image with a new one, the name doesn't change either.用新图像替换现有图像时,名称也不会改变。 Just the content of the image file changes.只是图像文件的内容发生了变化。

I think there are two types of simple solutions: 1) those which come to mind first (straightforward solutions, because they are easy to come up with), 2) those which you end up with after thinking things over (because they are easy to use).我认为有两种简单的解决方案:1)首先想到的那些(直截了当的解决方案,因为它们很容易提出),2)您在考虑之后最终得出的那些(因为它们很容易利用)。 Apparently, you won't always benefit if you chose to think things over.显然,如果您选择重新考虑,您将不会总是受益。 But the second options is rather underestimated, I believe.但我相信第二种选择被低估了。 Just think why php is so popular ;)想想为什么php如此受欢迎;)

use Class="NO-CACHE"使用Class="NO-CACHE"

sample html:示例 html:

<div>
    <img class="NO-CACHE" src="images/img1.jpg" />
    <img class="NO-CACHE" src="images/imgLogo.jpg" />
</div>

jQuery: jQuery:

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

javascript: 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"结果:src="images/img1.jpg" => src="images/img1.jpg?a=0.08749723793963926"

You may write a proxy script for serving images - that's a bit more of work though.您可以编写一个代理脚本来提供图像——不过这需要更多的工作。 Something likes this:像这样的东西:

HTML: HTML:

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

Script:脚本:

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

Actually either no-cache headers or random number at image src should be sufficient, but since we want to be bullet proof..实际上,图像 src 中的无缓存标头或随机数应该就足够了,但是因为我们想要防弹..

I checked all the answers around the web and the best one seemed to be: (actually it isn't)我检查了网络上的所有答案,最好的答案似乎是:(实际上不是)

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

at first.首先。

However, if you add cache=none parameter (which is static "none" word), it doesn't effect anything, browser still loads from cache.但是,如果您添加cache=none参数(这是静态“无”字),它不会影响任何东西,浏览器仍然从缓存加载。

Solution to this problem was:这个问题的解决方案是:

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

where you basically add unix timestamp to make the parameter dynamic and no cache, it worked.您基本上添加了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.但是,我的问题有点不同:我正在加载动态生成的 php 图表图像,并使用 $_GET 参数控制页面。 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.我希望在 URL GET 参数保持不变时从缓存中读取图像,并且在 GET 参数更改时不缓存。

To solve this problem, I needed to hash $_GET but since it is array here is the solution:为了解决这个问题,我需要散列 $_GET 但因为它是数组,所以这里是解决方案:

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

Edit :编辑

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() gets file modification time. filemtime() 获取文件修改时间。

When uploading an image, its filename is not kept in the database.上传图像时,其文件名不会保存在数据库中。 It is renamed as Image.jpg (to simply things out when using it).它被重命名为 Image.jpg(在使用它时简单地说明一下)。

Change this, and you've fixed your problem.改变这个,你就解决了你的问题。 I use timestamps, as with the solutions proposed above: Image-<timestamp>.jpg我使用时间戳,就像上面提出的解决方案一样: Image-<timestamp>.jpg

Presumably, whatever problems you're avoiding by keeping the same filename for the image can be overcome, but you don't say what they are.据推测,通过为图像保留相同的文件名而避免的任何问题都可以克服,但你没有说它们是什么。

I'm a NEW Coder, but here's what I came up with, to stop the Browser from caching and holding onto my webcam views:我是一名新的编码员,但这是我想出的,以阻止浏览器缓存并保留我的网络摄像头视图:

<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).不确定什么适用于什么浏览器,但它确实适用于某些浏览器:IE:在刷新网页和重新访问网站时工作(不刷新)。 CHROME: Works only when webpage is refreshed (even after a revisit). CHROME:仅在刷新网页时有效(即使在重新访问之后)。 SAFARI and iPad: Doesn't work, I have to clear the History & Web Data. SAFARI 和 iPad:不起作用,我必须清除历史记录和网络数据。

Any Ideas on SAFARI/ iPad?对 SAFARI/iPad 有什么想法吗?

You must use a unique filename(s).您必须使用唯一的文件名。 Like this像这样

<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="">

But you want it to never serve image from cache.但是您希望它永远不会从缓存中提供图像。 For this, if the page does not use page cache , it is possible with PHP or server side.为此,如果页面不使用页面缓存,则可以使用 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.原因:浏览器缓存...最后但最有效的方法是 Native JAVASCRIPT。 This simple code finds all images with a "NO-CACHE" class and makes the images almost unique.这个简单的代码查找所有具有“NO-CACHE”类的图像,并使图像几乎是唯一的。 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();
}

USAGE用法

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

RESULT(s) Like This结果像这样

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

Your problem is that despite the Expires: header, your browser is re-using its in-memory copy of the image from before it was updated, rather than even checking its cache.您的问题是,尽管有Expires:标头,但您的浏览器仍在重新使用更新之前的图像内存副本,而不是检查其缓存。

I had a very similar situation uploading product images in the admin backend for a store-like site, and in my case I decided the best option was to use javascript to force an image refresh, without using any of the URL-modifying techniques other people have already mentioned here.我在管理后端为类似商店的网站上传产品图片时遇到了非常相似的情况,就我而言,我认为最好的选择是使用 javascript 强制刷新图片,而不使用其他人的任何 URL 修改技术这里已经提到了。 Instead, I put the image URL into a hidden IFRAME, called location.reload(true) on the IFRAME's window, and then replaced my image on the page.相反,我将图像 URL 放入一个隐藏的 IFRAME,在 IFRAME 的窗口中调用location.reload(true) ,然后在页面上替换我的图像。 This forces a refresh of the image, not just on the page I'm on, but also on any later pages I visit - without either client or server having to remember any URL querystring or fragment identifier parameters.这会强制刷新图像,不仅在我所在的页面上,而且在我访问的任何后续页面上 - 客户端或服务器都不必记住任何 URL 查询字符串或片段标识符参数。

I posted some code to do this in my answer here .我在这里的答案中发布了一些代码来执行此操作。

From my point of view, disable images caching is a bad idea.从我的角度来看,禁用图像缓存是一个坏主意。 At all.完全没有。

The root problem here is - how to force browser to update image, when it has been updated on a server side.这里的根本问题是 - 如何在服务器端更新图像时强制浏览器更新图像。

Again, from my personal point of view, the best solution is to disable direct access to images.同样,从我个人的角度来看,最好的解决方案是禁用对图像的直接访问。 Instead access images via server-side filter/servlet/other similar tools/services.而是通过服务器端过滤器/servlet/其他类似工具/服务访问图像。

In my case it's a rest service, that returns image and attaches ETag in response.在我的情况下,它是一个休息服务,它返回图像并附加 ETag 作为响应。 The service keeps hash of all files, if file is changed, hash is updated.该服务保留所有文件的哈希,如果文件更改,则更新哈希。 It works perfectly in all modern browsers.它在所有现代浏览器中都能完美运行。 Yes, it takes time to implement it, but it is worth it.是的,实施它需要时间,但这是值得的。

The only exception - are favicons.唯一的例外 - 是网站图标。 For some reasons, it does not work.由于某些原因,它不起作用。 I could not force browser to update its cache from server side.我无法强制浏览器从服务器端更新其缓存。 ETags, Cache Control, Expires, Pragma headers, nothing helped. ETags、Cache Control、Expires、Pragma headers,没有任何帮助。

In this case, adding some random/version parameter into url, it seems, is the only solution.在这种情况下,似乎在 url 中添加一些随机/版本参数是唯一的解决方案。

Add a time stamp <img src="picture.jpg?t=<?php echo time();?>">添加时间戳<img src="picture.jpg?t=<?php echo time();?>">

will always give your file a random number at the end and stop it caching总是会在最后给你的文件一个随机数并停止缓存

With the potential for badly behaved transparent proxies in between you and the client, the only way to totally guarantee that images will not be cached is to give them a unique uri, something like tagging a timestamp on as a query string or as part of the path.由于您和客户端之间可能存在行为不良的透明代理,因此完全保证图像不会被缓存的唯一方法是给它们一个唯一的 uri,例如将时间戳标记为查询字符串或作为小路。

If that timestamp corresponds to the last update time of the image, then you can cache when you need to and serve the new image at just the right time.如果该时间戳对应于图像的最后更新时间,那么您可以在需要时缓存并在正确的时间提供新图像。

I assume original question regards images stored with some text info.我假设原始问题与存储有一些文本信息的图像有关。 So, if you have access to a text context when generating src=... url, consider store/use CRC32 of image bytes instead of meaningless random or time stamp.因此,如果您在生成 src=... url 时可以访问文本上下文,请考虑存储/使用图像字节的 CRC32,而不是无意义的随机或时间戳。 Then, if the page with plenty of images is displaying, only updated images will be reloaded.然后,如果显示有大量图像的页面,则只会重新加载更新的图像。 Eventually, if CRC storing is impossible, it can be computed and appended to the url at runtime.最终,如果 CRC 存储是不可能的,它可以在运行时计算并附加到 url。

Ideally, you should add a button/keybinding/menu to each webpage with an option to synchronize content.理想情况下,您应该为每个网页添加一个按钮/键绑定/菜单,并带有同步内容的选项。

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.为此,您将跟踪可能需要同步的资源,并使用 xhr 使用动态查询字符串探测图像,或者在运行时使用 src 使用动态查询字符串创建图像。 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.然后使用广播机制通知正在使用该资源的网页的所有组件更新以使用附加到其 url 的动态查询字符串的资源。

A naive example looks like this:一个天真的示例如下所示:

Normally, the image is displayed and cached, but if the user pressed the button, an xhr request is sent to the resource with a time querystring appended to it;通常,图像会显示并缓存,但如果用户按下按钮,则会向资源发送一个 xhr 请求,并附加一个时间查询字符串; since the time can be assumed to be different on each press, it will make sure that the browser will bypass cache since it can't tell whether the resource is dynamically generated on the server side based on the query, or if it is a static resource that ignores query.由于可以假设每次按下的时间都不同,因此它将确保浏览器将绕过缓存,因为它无法判断资源是基于查询在服务器端动态生成的,还是静态的忽略查询的资源。

The result is that you can avoid having all your users bombard you with resource requests all the time, but at the same time, allow a mechanism for users to update their resources if they suspect they are out of sync.结果是,您可以避免让所有用户一直用资源请求轰炸您,但同时,允许用户在怀疑资源不同步时更新其资源的机制。

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

All the Answers are valid as it works fine.所有答案都是有效的,因为它工作正常。 But with that, the browser also creates another file in the cache every time it loads that image with a different URL.但是这样一来,浏览器也会在每次使用不同的 URL 加载该图像时在缓存中创建另一个文件。 So instead of changing the URL by adding some query params to it.因此,不要通过向 URL 添加一些查询参数来更改 URL。

So, what we can do is we can update the browser cache using cache.put所以,我们可以做的是我们可以使用cache.put更新浏览器缓存

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

cache.put updates the cache with a new response. cache.put用新的响应更新缓存。

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

I've found Chrome specifically tries to get clever with the URL arguments solution on images.我发现 Chrome 专门尝试使用图像上的 URL 参数解决方案变得聪明。 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 (Eg time stamp or file version) AND also change the capitalisation of the image file extension in the URL.我发现的最可靠的解决方案是添加 URL 参数(例如时间戳或文件版本)更改 URL 中图像文件扩展名的大小写。

<img src="picture.jpg">

becomes变成

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

I made a PHP script that automatically appends the timestamps on all images and also on links.我制作了一个 PHP 脚本,它会自动在所有图像和链接上附加时间戳。 You just need to include this script in your pages.你只需要在你的页面中包含这个脚本。 Enjoy!享受!

http://alv90.altervista.org/how-to-force-the-browser-not-to-cache-images/ 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">最好的解决方案是在源 href 的末尾提供当前时间,例如<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.要获取最近的时间,可以在 jQuery 或 javascript 中使用performance.now()函数。

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

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