JavaScript:如何强制 Image() 不使用浏览器缓存?

问题描述 投票:0回答:5

如果我在浏览器中手动加载 nextimg URL,每次重新加载时它都会给出一张新图片。但是这段代码每次迭代都会显示相同的图像

draw()

如何强制不缓存 myimg?

<html>
  <head>
    <script type="text/javascript">
      function draw(){
        var canvas = document.getElementById('canv');
        var ctx = canvas.getContext('2d');
        var rx;
        var ry;
        var i;

        myimg = new Image();
        myimg.src = 'http://ohm:8080/cgi-bin/nextimg'

        rx=Math.floor(Math.random()*100)*10
        ry=Math.floor(Math.random()*100)*10
        ctx.drawImage(myimg,rx,ry);
        window.setTimeout('draw()',0);
      }
    </script>
  </head>
  <body onload="draw();">
    <canvas id="canv" width="1024" height="1024"></canvas>
  </body>
</html>
javascript image caching
5个回答
26
投票

最简单的方法是将不断变化的查询字符串放在末尾:

var url = 'http://.../?' + escape(new Date())

有些人更喜欢使用

Math.random()
而不是
escape(new Date())
。但正确的方法可能是更改 Web 服务器发送的标头以禁止缓存。


9
投票

你无法阻止它在 Javascript 中完全缓存图像。但是,您可以使用图像的 src/地址来强制它重新缓存:

[Image].src = 'image.png?' + (new Date()).getTime();

您可以采用任何 Ajax 缓存解决方案并在此处应用它。


5
投票

这实际上听起来像是浏览器中的错误 - 如果是在 Safari 中,您可以在 http://bugs.webkit.org 提交文件,或者在 Firefox 中在 https://bugzilla.mozilla.org/ 提交文件。 为什么我说潜在的浏览器错误? 因为浏览器意识到它不应该在重新加载时缓存,但当您以编程方式请求它时,它确实会为您提供图像的缓存副本。

那你确定你真的在画东西吗? Canvas.drawImage API 不会等待图像加载,并且当您尝试使用它时,如果图像尚未完全加载,则不会绘制。

更好的做法是这样的:

    var myimg = new Image();
    myimg.onload = function() {
        var rx=Math.floor(Math.random()*100)*10
        var ry=Math.floor(Math.random()*100)*10
        ctx.drawImage(myimg,rx,ry);
        window.setTimeout(draw,0);
    }
    myimg.src = 'http://ohm:8080/cgi-bin/nextimg'

(您也可以将

draw
作为参数传递给 setTimeout,而不是使用字符串,这将节省一遍又一遍地重新解析和编译同一字符串。)


0
投票

实际上,您需要绕过这里的两个缓存:一个是常规 HTTP 缓存,您可以通过在图像上使用正确的 HTTP 标头来避免。 但您还必须阻止浏览器重新使用图像的内存副本;如果它决定可以做到这一点,它甚至永远不会查询其缓存,因此 HTTP 标头将无济于事。

为了防止这种情况,您可以使用更改的查询字符串或更改的片段标识符。

请参阅我的帖子这里了解更多详情。


0
投票

这是关于处理这种情况的 2024 年更新,我用它来组织和解决有关此问题的一些答案和评论。

客户端解决方案

假设你有:

var url = 'http://website.com/20.jpg'

如果您无法控制服务器,处理这种情况的最简单方法是:

var date = encodeURI(new Date())
img.src = `${url}?${date}`

以下方法通常也有效,但等效随机数之间有(远程)冲突的可能性。如果你想百分百安全,只需使用第一种方法:

var rand = Math.random()
img.src = `${url}?${rand}`

Dan 的回答 的评论中有人建议使用

Cache-Control: no-cache
来处理客户端请求。不幸的是,这种方法有两个问题:

  1. 它要求服务器可靠地实现
    If-Modified-Since
    If-None-Match
    请求标头,如此答案中所述。
  2. 即使服务器已经正确实现了这些标头(或者即使您决定使用更强大的
    Cache-Control: no-store
    标头,不需要这些标头来破坏缓存),也没有可靠的方法来告诉服务器您想要的将
    Cache-Control
    标头用于 image
    src
    请求
    ,如此问题的答案中所述。如果您正在执行
    fetch
    请求,那么请务必使用 这个答案 中的方法来设置
    Cache-Control
    标头。

服务器端解决方案

如果您可以控制服务器,则可以为请求设置

Cache-Control
标头服务器端。如上所述,如果您想要最佳缓存,则需要实现
If-Modified-Since
If-None-Match
。如果您只想完全消除缓存,只需设置
Cache-Control: no-store

以下是在 Go 中如何做到这一点:

func ServeMedia(w http.ResponseWriter, b []byte) {
    w.Header().Set("Content-Type", "application/octet-stream")
    // Eliminate caching so that reused image names will refresh.
    w.Header().Set("Cache-Control", "no-store")
    w.Write(b)
}
© www.soinside.com 2019 - 2024. All rights reserved.