刷新图像与一个新的一个在相同的url

我正在访问我的网站上的一个链接,每次访问它都会提供一个新的图像。

我遇到的问题是,如果我试图在后台加载图像,然后更新页面上的图像,图像不会改变——尽管在我重新加载页面时它会更新。

var newImage = new Image();
newImage.src = "http://localhost/image.jpg";


function updateImage()
{
if(newImage.complete) {
document.getElementById("theText").src = newImage.src;
newImage = new Image();
number++;
newImage.src = "http://localhost/image/id/image.jpg?time=" + new Date();
}


setTimeout(updateImage, 1000);
}

FireFox看到的头文件:

HTTP/1.x 200 OK
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: image/jpeg
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Server: Microsoft-HTTPAPI/1.0
Date: Thu, 02 Jul 2009 23:06:04 GMT

我需要强制刷新页面上的图像。什么好主意吗?

497655 次浏览

尝试在url的末尾添加cachebreaker:

newImage.src = "http://localhost/image.jpg?" + new Date().getTime();

这将在创建图像时自动附加当前时间戳,并且它将使浏览器重新查找图像,而不是从缓存中检索图像。

尝试使用一个没有价值的查询字符串使其成为一个唯一的url:

function updateImage()
{
if(newImage.complete) {
document.getElementById("theText").src = newImage.src;
newImage = new Image();
number++;
newImage.src = "http://localhost/image.jpg?" + new Date();
}


setTimeout(updateImage, 1000);
}

一种解决方法是像建议的那样笨拙地添加一些get查询参数。

更好的答案是在HTTP报头中发出两个额外的选项。

Pragma: no-cache
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Cache-Control: no-cache, must-revalidate

通过提供过去的日期,它不会被浏览器缓存。Cache-Control是在HTTP/1.1中添加的,必须重新验证标记表明代理永远不应该提供旧的映像,即使是在可减轻的情况下,并且Pragma: no-cache对于当前的现代浏览器/缓存并不是真正必要的,但可能有助于一些复杂的破碎的旧实现。

在创建新图像之后,是否从DOM中删除旧图像并用新图像替换它?

您可以在每次updateImage调用时抓取新图像,但不将它们添加到页面。

有很多方法可以做到这一点。像这样的东西是可行的。

function updateImage()
{
var image = document.getElementById("theText");
if(image.complete) {
var new_image = new Image();
//set up the new image
new_image.id = "theText";
new_image.src = image.src;
// insert new image and remove old
image.parentNode.insertBefore(new_image,image);
image.parentNode.removeChild(image);
}


setTimeout(updateImage, 1000);
}

在得到工作后,如果仍然有问题,它可能是缓存问题,就像其他答案谈论。

我最终要做的是让服务器将对该目录下的图像的任何请求映射到我试图更新的源。然后,我让计时器在名称的末尾附加一个数字,这样DOM就会将其视为新图像并加载它。

如。

http://localhost/image.jpg
//and
http://localhost/image01.jpg

将请求相同的图像生成代码,但它将看起来像不同的图像浏览器。

var newImage = new Image();
newImage.src = "http://localhost/image.jpg";
var count = 0;
function updateImage()
{
if(newImage.complete) {
document.getElementById("theText").src = newImage.src;
newImage = new Image();
newImage.src = "http://localhost/image/id/image" + count++ + ".jpg";
}
setTimeout(updateImage, 1000);
}

作为……的替代方案。

newImage.src = "http://localhost/image.jpg?" + new Date().getTime();

...看来……

newImage.src = "http://localhost/image.jpg#" + new Date().getTime();

...足以欺骗浏览器缓存而不绕过任何上游缓存,假设你返回了正确的Cache-Control头。虽然你可以用…

Cache-Control: no-cache, must-revalidate

...你就失去了If-Modified-SinceIf-None-Match头文件的好处,所以……

Cache-Control: max-age=0, must-revalidate

...应该防止浏览器重新下载整个图像,如果它实际上没有改变。在IE, Firefox和Chrome上进行测试和工作。令人恼火的是,它在Safari上失败了,除非你使用…

Cache-Control: no-store

...尽管这可能比用数百个相同的映像填充上游缓存更可取,特别是当它们运行在您自己的服务器上时。: -)

更新(2014-09-28):现在看起来Chrome也需要Cache-Control: no-store

我通过servlet将数据发送回来解决了这个问题。

response.setContentType("image/png");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache, must-revalidate");
response.setDateHeader("Expires", 0);


BufferedImage img = ImageIO.read(new File(imageFileName));


ImageIO.write(img, "png", response.getOutputStream());

然后从页面中给它一个带有一些参数的servlet,以获取正确的图像文件。

<img src="YourServlet?imageFileName=imageNum1">

关于如何做到这一点,我已经看到了很多不同的答案,所以我想在这里总结一下(加上我自己发明的第4种方法):


(1)在URL中添加一个唯一的缓存破坏查询参数,例如:

newImage.src = "image.jpg?t=" + new Date().getTime();

优点: 100%可靠,快速;易于理解和实现。

缺点:完全绕过缓存,这意味着当图像在视图之间改变时,不必要的延迟和带宽使用。将潜在地填满浏览器缓存(和任何中间缓存)与许多,许多完全相同的图像的副本!另外,需要修改图像URL。

使用时间:当图像不断变化时使用,例如用于实时网络摄像头馈送。如果你使用这个方法,确保图像本身带有Cache-control: no-cache HTTP头!!(通常可以使用.htaccess文件设置)。否则,您将逐步用旧版本的图像填充缓存!


(2)在URL中添加查询参数,该参数仅在文件更改时才更改,例如:

echo '<img src="image.jpg?m=' . filemtime('image.jpg') . '">';

(这是PHP服务器端代码,但这里重要的一点是文件名后面附加了?m=[文件最后修改时间]查询字符串)。

优点: 100%可靠,快速;而且易于理解和实现,完美地保留了缓存的优势。

缺点:需要修改图像URL。此外,服务器还需要做一些工作——它必须访问文件最后修改的时间。此外,它需要服务器端信息,因此不适合纯客户端解决方案来检查刷新映像。

使用时间:当你想缓存图像,但可能需要在服务器端不时更新它们,而不改变文件名本身。AND时,您可以轻松地确保将正确的查询字符串添加到HTML中的每个图像实例中。


(3)为你的图像提供Cache-control: max-age=0, must-revalidate标题,并在URL中添加一个唯一的memcache-busting片段标识符,例如:

newImage.src = "image.jpg#" + new Date().getTime();

这里的想法是缓存控制头将图像放在浏览器缓存中,但立即将它们标记为陈旧的,因此每次重新显示它们时,浏览器必须与服务器检查它们是否已更改。这确保浏览器的HTTP缓存总是返回图像的最新副本。然而,浏览器通常会重用内存中的图像副本(如果有的话),在这种情况下甚至不会检查HTTP缓存。为了防止这种情况,可以使用片段标识符:内存映像src的比较包含片段标识符,但在查询HTTP缓存之前将其剥离。(因此,例如,image.jpg#Aimage.jpg#B都可以从浏览器的HTTP缓存中的image.jpg条目中显示,但image.jpg#B永远不会使用上次显示image.jpg#A时的内存保留图像数据显示)。

优点:正确使用HTTP缓存机制,并使用缓存的图像,如果他们没有改变。适用于被添加到静态图像URL的查询字符串阻塞的服务器(因为服务器永远不会看到片段标识符-它们只供浏览器自己使用)。

缺点:依赖于浏览器的一些可疑(或至少记录不清楚)的行为,关于在其url中带有片段标识符的图像(然而,我已经在FF27, Chrome33和IE11中成功地测试了这一点)。仍然为每个图像视图向服务器发送重新验证请求,如果图像很少更改和/或延迟是一个大问题(因为即使缓存的图像仍然良好,您也需要等待重新验证响应),这可能是多余的。需要修改图像url。

使用时间:当图像可能频繁更改,或需要由客户端间歇刷新而不涉及服务器端脚本,但你仍然想要缓存的优势时使用。例如,轮询每隔几分钟就会不定期更新图像的实时网络摄像头。或者,如果你的服务器不允许静态图像url上的查询字符串,使用(1)或(2)代替。

[EDIT 2021:不再适用于最近的Chrome &Edge:这些浏览器中的内部memcache现在忽略了片段标识符(可能是因为切换到Blink引擎?)但是请参阅下面的方法(4),现在在这两种浏览器上要容易得多,所以考虑将此方法与(4)的简化版本结合起来,以覆盖这两种浏览器]


(4)使用Javascript强制刷新特定的图像,首先将其加载到隐藏的<iframe>中,然后在iframe的contentWindow上调用location.reload(true)

步骤如下:

  • 加载要刷新的图像到一个隐藏的iframe。[EDIT 2021:对于Chrome和Edge,加载带有<img>标记的HTML页面,而不是原始图像文件]这只是一个设置步骤——如果需要的话,它可以在实际刷新之前很长时间完成。即使图像在这个阶段加载失败也没关系!

  • 一旦完成,清空页面上或任何DOM节点(甚至是存储在javascript变量中的页面外的)中的所有图像副本。这是必要的,因为浏览器可能会从过期的内存副本中显示映像(IE11尤其会这样做):在刷新HTTP缓存之前,您需要确保所有内存中副本都被清除。如果其他javascript代码正在异步运行,您可能还需要防止该代码同时创建要刷新的图像的新副本。

  • < p > iframe.contentWindow.location.reload(true)打电话。true强制缓存绕过,直接从服务器重新加载并覆盖现有的缓存副本。

  • 一旦它完成了__abc1 -加载,恢复空白图像。他们现在应该显示来自服务器的新版本!

对于同域图像,可以直接将图像加载到iframe中。对于跨域图像,你必须加载一个HTML页面从你的领域,其中包含一个<img>标记的图像,否则你会得到一个“访问被拒绝”;错误时,试图调用iframe.contentWindow.reload(...)[Chrome &边也。< / >强

优点:的工作原理就像你在DOM中希望的image.reload()函数一样!允许正常缓存图像(如果你想要它们,甚至在未来的过期日期,从而避免频繁的重新验证)。允许您仅使用客户端代码刷新特定图像,而无需更改当前页面或任何其他页面上该图像的url。

缺点:依赖于Javascript。不能100%保证在每个浏览器都能正常工作(我已经在FF27、Chrome33和IE11上测试成功了)。相对于其他方法非常复杂。[EDIT 2021:除非你只需要最新的Chrome &边缘支持,在这种情况下非常简单].

使用时间:当你有一个基本静态图像的集合,你想要缓存,但你仍然需要能够偶尔更新它们,并获得更新发生的即时视觉反馈。(特别是当仅仅刷新整个浏览器页面无法工作时,例如在一些基于AJAX构建的web应用程序中)。当方法(1)-(3)不可行的时候,因为(无论出于什么原因)你不能更改所有可能显示你需要更新的图像的url。(注意,使用这3种方法,图像将被刷新,但如果另一个页面试图显示图像没有适当的查询字符串或片段标识符,它可能会显示一个旧版本)。

以一种非常健壮和灵活的方式实现这一点的细节如下:

让我们假设你的网站在URL路径/img/1x1blank.gif处包含一个空白的1x1像素。gif,并且在URL路径/echoimg.php处也有以下一行PHP脚本(只需要应用强制刷新跨域图像,当然可以用任何服务器端脚本语言重写):

<img src="<?=htmlspecialchars(@$_GET['src'],ENT_COMPAT|ENT_HTML5,'UTF-8')?>">

然后,这里是如何在Javascript中实现所有这些的现实实现。它看起来有点复杂,但有很多注释,重要的函数只是forceImgReload() -前两个只是空白和非空白的图像,应该设计为与您自己的HTML有效地工作,所以编码它们最适合您;它们中的许多复杂之处对你的网站来说可能是不必要的:

// This function should blank all images that have a matching src, by changing their src property to /img/1x1blank.gif.
// ##### You should code the actual contents of this function according to your page design, and what images there are on them!!! #####
// Optionally it may return an array (or other collection or data structure) of those images affected.
// This can be used by imgReloadRestore() to restore them later, if that's an efficient way of doing it (otherwise, you don't need to return anything).
// NOTE that the src argument here is just passed on from forceImgReload(), and MAY be a relative URI;
// However, be aware that if you're reading the src property of an <img> DOM object, you'll always get back a fully-qualified URI,
// even if the src attribute was a relative one in the original HTML.  So watch out if trying to compare the two!
// NOTE that if your page design makes it more efficient to obtain (say) an image id or list of ids (of identical images) *first*, and only then get the image src,
// you can pass this id or list data to forceImgReload() along with (or instead of) a src argument: just add an extra or replacement parameter for this information to
// this function, to imgReloadRestore(), to forceImgReload(), and to the anonymous function returned by forceImgReload() (and make it overwrite the earlier parameter variable from forceImgReload() if truthy), as appropriate.
function imgReloadBlank(src)
{
// ##### Everything here is provisional on the way the pages are designed, and what images they contain; what follows is for example purposes only!
// ##### For really simple pages containing just a single image that's always the one being refreshed, this function could be as simple as just the one line:
// ##### document.getElementById("myImage").src = "/img/1x1blank.gif";


var blankList = [],
fullSrc = /* Fully qualified (absolute) src - i.e. prepend protocol, server/domain, and path if not present in src */,
imgs, img, i;


for each (/* window accessible from this one, i.e. this window, and child frames/iframes, the parent window, anything opened via window.open(), and anything recursively reachable from there */)
{
// get list of matching images:
imgs = theWindow.document.body.getElementsByTagName("img");
for (i = imgs.length; i--;) if ((img = imgs[i]).src===fullSrc)  // could instead use body.querySelectorAll(), to check both tag name and src attribute, which would probably be more efficient, where supported
{
img.src = "/img/1x1blank.gif";  // blank them
blankList.push(img);            // optionally, save list of blanked images to make restoring easy later on
}
}


for each (/* img DOM node held only by javascript, for example in any image-caching script */) if (img.src===fullSrc)
{
img.src = "/img/1x1blank.gif";   // do the same as for on-page images!
blankList.push(img);
}


// ##### If necessary, do something here that tells all accessible windows not to create any *new* images with src===fullSrc, until further notice,
// ##### (or perhaps to create them initially blank instead and add them to blankList).
// ##### For example, you might have (say) a global object window.top.blankedSrces as a propery of your topmost window, initially set = {}.  Then you could do:
// #####
// #####     var bs = window.top.blankedSrces;
// #####     if (bs.hasOwnProperty(src)) bs[src]++; else bs[src] = 1;
// #####
// ##### And before creating a new image using javascript, you'd first ensure that (blankedSrces.hasOwnProperty(src)) was false...
// ##### Note that incrementing a counter here rather than just setting a flag allows for the possibility that multiple forced-reloads of the same image are underway at once, or are overlapping.


return blankList;   // optional - only if using blankList for restoring back the blanked images!  This just gets passed in to imgReloadRestore(), it isn't used otherwise.
}








// This function restores all blanked images, that were blanked out by imgReloadBlank(src) for the matching src argument.
// ##### You should code the actual contents of this function according to your page design, and what images there are on them, as well as how/if images are dimensioned, etc!!! #####
function imgReloadRestore(src,blankList,imgDim,loadError);
{
// ##### Everything here is provisional on the way the pages are designed, and what images they contain; what follows is for example purposes only!
// ##### For really simple pages containing just a single image that's always the one being refreshed, this function could be as simple as just the one line:
// ##### document.getElementById("myImage").src = src;


// ##### if in imgReloadBlank() you did something to tell all accessible windows not to create any *new* images with src===fullSrc until further notice, retract that setting now!
// ##### For example, if you used the global object window.top.blankedSrces as described there, then you could do:
// #####
// #####     var bs = window.top.blankedSrces;
// #####     if (bs.hasOwnProperty(src)&&--bs[src]) return; else delete bs[src];  // return here means don't restore until ALL forced reloads complete.


var i, img, width = imgDim&&imgDim[0], height = imgDim&&imgDim[1];
if (width) width += "px";
if (height) height += "px";


if (loadError) {/* If you want, do something about an image that couldn't load, e.g: src = "/img/brokenImg.jpg"; or alert("Couldn't refresh image from server!"); */}


// If you saved & returned blankList in imgReloadBlank(), you can just use this to restore:


for (i = blankList.length; i--;)
{
(img = blankList[i]).src = src;
if (width) img.style.width = width;
if (height) img.style.height = height;
}
}








// Force an image to be reloaded from the server, bypassing/refreshing the cache.
// due to limitations of the browser API, this actually requires TWO load attempts - an initial load into a hidden iframe, and then a call to iframe.contentWindow.location.reload(true);
// If image is from a different domain (i.e. cross-domain restrictions are in effect, you must set isCrossDomain = true, or the script will crash!
// imgDim is a 2-element array containing the image x and y dimensions, or it may be omitted or null; it can be used to set a new image size at the same time the image is updated, if applicable.
// if "twostage" is true, the first load will occur immediately, and the return value will be a function
// that takes a boolean parameter (true to proceed with the 2nd load (including the blank-and-reload procedure), false to cancel) and an optional updated imgDim.
// This allows you to do the first load early... for example during an upload (to the server) of the image you want to (then) refresh.
function forceImgReload(src, isCrossDomain, imgDim, twostage)
{
var blankList, step = 0,                                // step: 0 - started initial load, 1 - wait before proceeding (twostage mode only), 2 - started forced reload, 3 - cancelled
iframe = window.document.createElement("iframe"),   // Hidden iframe, in which to perform the load+reload.
loadCallback = function(e)                          // Callback function, called after iframe load+reload completes (or fails).
{                                                   // Will be called TWICE unless twostage-mode process is cancelled. (Once after load, once after reload).
if (!step)  // initial load just completed.  Note that it doesn't actually matter if this load succeeded or not!
{
if (twostage) step = 1;  // wait for twostage-mode proceed or cancel; don't do anything else just yet
else { step = 2; blankList = imgReloadBlank(src); iframe.contentWindow.location.reload(true); }  // initiate forced-reload
}
else if (step===2)   // forced re-load is done
{
imgReloadRestore(src,blankList,imgDim,(e||window.event).type==="error");    // last parameter checks whether loadCallback was called from the "load" or the "error" event.
if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
}
}
iframe.style.display = "none";
window.parent.document.body.appendChild(iframe);    // NOTE: if this is done AFTER setting src, Firefox MAY fail to fire the load event!
iframe.addEventListener("load",loadCallback,false);
iframe.addEventListener("error",loadCallback,false);
iframe.src = (isCrossDomain ? "/echoimg.php?src="+encodeURIComponent(src) : src);  // If src is cross-domain, script will crash unless we embed the image in a same-domain html page (using server-side script)!!!
return (twostage
? function(proceed,dim)
{
if (!twostage) return;
twostage = false;
if (proceed)
{
imgDim = (dim||imgDim);  // overwrite imgDim passed in to forceImgReload() - just in case you know the correct img dimensions now, but didn't when forceImgReload() was called.
if (step===1) { step = 2; blankList = imgReloadBlank(src); iframe.contentWindow.location.reload(true); }
}
else
{
step = 3;
if (iframe.contentWindow.stop) iframe.contentWindow.stop();
if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
}
}
: null);
}

然后,要强制刷新与页面位于同一域的图像,您可以这样做:

forceImgReload("myimage.jpg");

从其他地方(跨域)刷新一个图像:

forceImgReload("http://someother.server.com/someimage.jpg", true);

更高级的应用程序可能是在将新版本上载到服务器后重新加载图像,在上传的同时准备重新加载过程的初始阶段,以尽量减少用户可见的重新加载延迟。如果你通过AJAX上传,服务器返回一个非常简单的JSON数组[success, width, height],那么你的代码可能是这样的:

// fileForm is a reference to the form that has a the <input typ="file"> on it, for uploading.
// serverURL is the url at which the uploaded image will be accessible from, once uploaded.
// The response from uploadImageToServer.php is a JSON array [success, width, height]. (A boolean and two ints).
function uploadAndRefreshCache(fileForm, serverURL)
{
var xhr = new XMLHttpRequest(),
proceedWithImageRefresh = forceImgReload(serverURL, false, null, true);
xhr.addEventListener("load", function(){ var arr = JSON.parse(xhr.responseText); if (!(arr&&arr[0])) { proceedWithImageRefresh(false); doSomethingOnUploadFailure(...); } else { proceedWithImageRefresh(true,[arr[1],ar[2]]); doSomethingOnUploadSuccess(...); }});
xhr.addEventListener("error", function(){ proceedWithImageRefresh(false); doSomethingOnUploadError(...); });
xhr.addEventListener("abort", function(){ proceedWithImageRefresh(false); doSomethingOnUploadAborted(...); });
// add additional event listener(s) to track upload progress for graphical progress bar, etc...
xhr.open("post","uploadImageToServer.php");
xhr.send(new FormData(fileForm));
}

最后注意:虽然这个主题是关于图像的,但它也可能适用于其他类型的文件或资源。例如,防止使用过时的脚本或css文件,或者甚至刷新更新后的PDF文档(仅在设置为在浏览器中打开时使用(4))。在这些情况下,方法(4)可能需要对上面的javascript进行一些更改。

.
function reloadImage(imageId)
{
path = '../showImage.php?cache='; //for example
imageObject = document.getElementById(imageId);
imageObject.src = path + (new Date()).getTime();
}
<img src='../showImage.php' id='myimage' />


<br/>


<input type='button' onclick="reloadImage('myimage')" />

这是我的解决方案。这很简单。帧调度可以更好。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Image Refresh</title>
</head>


<body>


<!-- Get the initial image. -->
<img id="frame" src="frame.jpg">


<script>
// Use an off-screen image to load the next frame.
var img = new Image();


// When it is loaded...
img.addEventListener("load", function() {


// Set the on-screen image to the same source. This should be instant because
// it is already loaded.
document.getElementById("frame").src = img.src;


// Schedule loading the next frame.
setTimeout(function() {
img.src = "frame.jpg?" + (new Date).getTime();
}, 1000/15); // 15 FPS (more or less)
})


// Start the loading process.
img.src = "frame.jpg?" + (new Date).getTime();
</script>
</body>
</html>

下面的例子主要基于Doin的#4代码,利用document.write而不是iframe中的src来支持CORS,极大地简化了该代码。也只关注破坏浏览器缓存,而不是重新加载页面上的每个图像。

下面是用typescript编写的,并使用了angular 美元的问承诺库,只是供参考,但应该很容易移植到香草javascript。方法意味着存在于typescript类中。

返回一个承诺,该承诺将在iframe完成重新加载时得到解决。没有经过严格测试,但对我们来说很好。

    mmForceImgReload(src: string): ng.IPromise<void> {
var deferred = $q.defer<void>();
var iframe = window.document.createElement("iframe");


var firstLoad = true;
var loadCallback = (e) => {
if (firstLoad) {
firstLoad = false;
iframe.contentWindow.location.reload(true);
} else {
if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
deferred.resolve();
}
}
iframe.style.display = "none";
window.parent.document.body.appendChild(iframe);
iframe.addEventListener("load", loadCallback, false);
iframe.addEventListener("error", loadCallback, false);
var doc = iframe.contentWindow.document;
doc.open();
doc.write('<html><head><title></title></head><body><img src="' + src + '"></body></html>');
doc.close();
return deferred.promise;
}
document.getElementById("img-id").src = document.getElementById("img-id").src

将自己的SRC设置为自己的SRC。

我有一个要求:1)不能添加任何?var=xx到图像2)它应该跨域工作

我真的很喜欢这个答案中的#4选项,但是:

  • 它在可靠地跨域工作方面存在问题(并且需要修改服务器代码)。

我的捷径是:

  1. 创建隐藏iframe
  2. 将当前页面加载到它(是的,整个页面)
  3. iframe.contentWindow.location.reload(true);
  4. 重新设置图像源为其本身

在这里

function RefreshCachedImage() {
if (window.self !== window.top) return; //prevent recursion
var $img = $("#MYIMAGE");
var src = $img.attr("src");
var iframe = document.createElement("iframe");
iframe.style.display = "none";
window.parent.document.body.appendChild(iframe);
iframe.src = window.location.href;
setTimeout(function () {
iframe.contentWindow.location.reload(true);
setTimeout(function () {
$img.removeAttr("src").attr("src", src);
}, 2000);
}, 2000);
}

我知道,setTimeout。您必须将其更改为适当的onload-events。

我使用下面的概念,首先将图像绑定到一个虚假的(缓冲区)url,然后将其绑定到有效的url。

imgcover.ImageUrl = ConfigurationManager.AppSettings["profileLargeImgPath"] + "Myapp_CoverPic_" + userid + "Buffer.jpg";


imgcover.ImageUrl = ConfigurationManager.AppSettings["profileLargeImgPath"] + "Myapp_CoverPic_" + userid + ".jpg";

通过这种方式,我强制浏览器使用有效的url进行刷新。

<img src='someurl.com/someimage.ext' onload='imageRefresh(this, 1000);'>

然后在下面的一些javascript

<script language='javascript'>
function imageRefresh(img, timeout) {
setTimeout(function() {
var d = new Date;
var http = img.src;
if (http.indexOf("&d=") != -1) { http = http.split("&d=")[0]; }


img.src = http + '&d=' + d.getTime();
}, timeout);
}
</script>

这个做的是,当图像加载时,安排它在1秒内重新加载。我在不同类型的家庭安全摄像头的页面上使用这个。

下面的代码用于在单击按钮时刷新图像。

function reloadImage(imageId) {
imgName = 'vishnu.jpg'; //for example
imageObject = document.getElementById(imageId);
imageObject.src = imgName;
}


<img src='vishnu.jpg' id='myimage' />


<input type='button' onclick="reloadImage('myimage')" />

不需要new Date().getTime()恶作剧。你可以通过使用jQuery .load()创建一个不可见的虚拟图像来欺骗浏览器,然后每次创建一个新的图像:

<img src="" id="dummy", style="display:none;" />  <!-- dummy img -->
<div id="pic"></div>


<script type="text/javascript">
var url = whatever;
// You can repeat the following as often as you like with the same url
$("#dummy").load(url);
var image = new Image();
image.src = url;
$("#pic").html("").append(image);
</script>

简单的解决方案:在响应中添加以下报头:

Cache-control: no-store

为什么这样做在这个权威的页面中有清楚的解释:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control

这也解释了为什么no-cache不能工作。

其他答案并不适用,因为:

Caching.delete是关于一个新的缓存,你可以为离线工作创建,参见:https://web.dev/cache-api-quick-guide/

在URL中使用#的片段不起作用,因为#告诉浏览器不要向服务器发送请求。

一个随机添加到url的缓存破坏者可以工作,但也会填满浏览器缓存。在我的应用程序中,我想每隔几秒钟从网络摄像头下载一张5mb的图片。完全冻结你的电脑只需要一个小时或更少的时间。我仍然不知道为什么浏览器缓存不限制在一个合理的最大值,但这绝对是一个缺点。

我改进了脚本从AlexMA显示我的网络摄像头在网页上定期上传一个同名的新图像。我有问题,有时图像闪烁,因为一个破碎的图像或不完整(向上)加载的图像。为了防止闪烁,我检查了图像的自然高度,因为我的网络摄像头图像的大小没有改变。只有当加载的图像高度符合原始图像高度时,完整的图像才会显示在页面上。

  <h3>Webcam</h3>
<p align="center">
<img id="webcam" title="Webcam" onload="updateImage();" src="https://www.your-domain.com/webcam/current.jpg" alt="webcam image" width="900" border="0" />


<script type="text/javascript" language="JavaScript">


// off-screen image to preload next image
var newImage = new Image();
newImage.src = "https://www.your-domain.com/webcam/current.jpg";


// remember the image height to prevent showing broken images
var height = newImage.naturalHeight;


function updateImage()
{
// for sure if the first image was a broken image
if(newImage.naturalHeight > height)
{
height = newImage.naturalHeight;
}


// off-screen image loaded and the image was not broken
if(newImage.complete && newImage.naturalHeight == height)
{
// show the preloaded image on page
document.getElementById("webcam").src = newImage.src;
}


// preload next image with cachebreaker
newImage.src = "https://www.your-domain.com/webcam/current.jpg?time=" + new Date().getTime();


// refresh image (set the refresh interval to half of webcam refresh,
// in my case the webcam refreshes every 5 seconds)
setTimeout(updateImage, 2500);
}


</script>
</p>

在同一位置放置图像的第二个副本,然后删除原始图像。

function refreshImg(ele){
ele.insertAdjacentHTML('beforebegin',ele.outerHTML);
ele.parentNode.removeChild(ele);
}

这将有效地刷新图像。

CrossbrowserinsertAdjacentHTMLouterHTMLparentNoderemoveChild都是crossbrowser

在大多数情况下,性能损失几乎可以忽略不计。@Paolo柏甘蒂诺的 answer可能比这个函数更好。使用他的答案,只有一个DOM元素受到影响。这个函数有两个元素。

我在使用Unsplash随机图像功能时也遇到了同样的问题。在URL末尾添加一个虚拟查询字符串的想法是正确的,但在这种情况下,完全随机的参数不起作用(我尝试过)。我可以想象,对于其他一些服务也是一样的,但对于unsplash参数需要是sig,所以你的图像URL将是,例如,http://example.net/image.jpg?sig=RANDOM,其中random是一个随机字符串,当你更新它时,它不会是相同的。我使用Math.random()*100,但日期也合适。

您需要这样做,因为如果没有它,浏览器将看到所述路径上的图像已经加载,并将使用缓存的图像来加速加载。

看到https://github.com/unsplash/unsplash-source-js/issues/9

回答:你可以简单地使用获取并将缓存选项设置为'reload'来更新缓存:

fetch("my-image-url.jpg", {cache: 'reload', mode: 'no-cors'})

下面的函数将更新缓存而且,重新加载页面中的图像到处都是:

const reloadImg = url =>
fetch(url, { cache: 'reload', mode: 'no-cors' })
.then(() => document.body.querySelectorAll(`img[src='${url}']`)
.forEach(img => img.src = url))

它返回一个承诺,所以如果你愿意,你可以像await reloadImg("my-image-url.jpg")一样使用它。

现在取回API是几乎随处可见(当然IE上除外)。

这个答案基于上面的几个答案,但将它们稍加统一和简化,并将答案转换为JavaScript函数。

function refreshCachedImage(img_id) {
var img = document.getElementById(img_id);
img.src = img.src; // trick browser into reload
};

我需要解决动画svg在第一次玩完后不能重新启动的问题。

这个技巧也适用于其他媒体,如音频和视频。