如果我在浏览器中手动加载 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>
最简单的方法是将不断变化的查询字符串放在末尾:
var url = 'http://.../?' + escape(new Date())
有些人更喜欢使用
Math.random()
而不是 escape(new Date())
。但正确的方法可能是更改 Web 服务器发送的标头以禁止缓存。
你无法阻止它在 Javascript 中完全缓存图像。但是,您可以使用图像的 src/地址来强制它重新缓存:
[Image].src = 'image.png?' + (new Date()).getTime();
您可以采用任何 Ajax 缓存解决方案并在此处应用它。
这实际上听起来像是浏览器中的错误 - 如果是在 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,而不是使用字符串,这将节省一遍又一遍地重新解析和编译同一字符串。)
实际上,您需要绕过这里的两个缓存:一个是常规 HTTP 缓存,您可以通过在图像上使用正确的 HTTP 标头来避免。 但您还必须阻止浏览器重新使用图像的内存副本;如果它决定可以做到这一点,它甚至永远不会查询其缓存,因此 HTTP 标头将无济于事。
为了防止这种情况,您可以使用更改的查询字符串或更改的片段标识符。
请参阅我的帖子这里了解更多详情。
这是关于处理这种情况的 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
来处理客户端请求。不幸的是,这种方法有两个问题:
If-Modified-Since
和 If-None-Match
请求标头,如此答案中所述。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)
}