使用相同的网址刷新一张新图片


333

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

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

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

我需要强制刷新页面上的该图像。有任何想法吗?


Answers:


350

尝试在网址末尾添加一个cachebreaker:

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

创建图像时,这将自动附加当前时间戳,这将使浏览器再次查找该图像,而不是在缓存中检索该图像。


26
这不是一个很好的解决方案,因为它将淹没缓存(本地缓存和上游缓存)。Aya的答案有一个更好的解决方法。
Tgr 2012年

1
另外,在其他地方重新显示相同的图像,而以后没有“ cache breaker”,仍然显示旧的缓存版本(至少在firefox中)?和#:(
T4NK3R

3
您可以使用以下代码制作更少的代码:'image.jpg?' + (+new Date())
Lev Lukomsky 2015年

4
Date.now()
vp_arth

2
为什么不呢Math.random()
Gowtham Gopalakrishnan

227

我已经看到了很多有关如何执行此操作的答案的变体,所以我想我在这里进行了总结(加上我自己发明的第4种方法):


(1)在网址中添加唯一的缓存清除查询参数,例如:

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

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

缺点:完全绕过缓存,这意味着只要图像不存在,就不必要的延迟和带宽使用在视图之间改变。可能会用许多很多完全相同的图像副本填充浏览器缓存(和任何中间缓存)!另外,需要修改图像URL。

使用时间:当图像不断变化时使用,例如用于实时网络摄像头。如果使用此方法,请确保为图像本身提供Cache-control: no-cacheHTTP标头!!! (通常可以使用.htaccess文件进行设置)。否则,您将逐步用旧版本的图像填充缓存!


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

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

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

优点: 100%可靠,快速且易于理解和实施,并且完美保留了缓存优势。

缺点:需要修改图像URL。此外,服务器还需要做更多的工作-它必须有权访问文件的最后修改时间。此外,还需要服务器端信息,因此不适合用于仅客户端解决方案来检查刷新的图像。

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


(3)使用header为您的图像提供服务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都可能会从image.jpg浏览器的HTTP缓存中的条目中显示,但image.jpg#B永远不会使用image.jpg#A上次显示时的内存中保留图像数据来显示)。

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

缺点:对于URL中带有片段标识符的图像,依赖于浏览器的某种可疑行为(或至少记录不佳的行为)(但是,我已经在FF27,Chrome33和IE11中成功测试了此行为)。仍然会针对每个图像视图向服务器发送重新验证请求,如果仅很少更改图像和/或等待时间是个大问题,这可能会显得过高(因为即使在缓存的图像仍然良好的情况下,您也需要等待重新验证响应) 。需要修改图像URL。

什么时候使用:当图像可能经常更改或需要由客户端间歇刷新而不使用服务器端脚本的情况下使用,但是仍然需要缓存的优势。例如,轮询一个实时摄像头,该摄像头每隔几分钟会不定期地更新图像。或者,如果您的服务器不允许静态图像URL上的查询字符串,请使用(1)或(2)代替。


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

这些步骤是:

  • 将要刷新的图像加载到隐藏的iframe中。这只是一个设置步骤-如果需要,可以在实际刷新之前很长时间完成。图像在此阶段加载失败甚至都没有关系!

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

  • 致电iframe.contentWindow.location.reload(true)。该true部队缓存旁路,直接从服务器重装并覆盖现有的缓存副本。

  • 重新加载完成后,还原空白图像。他们现在应该显示服务器上的最新版本!

对于相同域的图像,您可以将图像直接加载到iframe中。对于跨域图像,您必须从域中加载一个HTML页面该页面中包含<img>标记中的图像,否则,在尝试调用时会出现“访问被拒绝”错误iframe.contentWindow.reload(...)

优点:就像您希望 DOM具有的image.reload()函数一样工作!允许按正常方式缓存图像(如果需要的话,即使有到期日期,也可以这样,从而避免了频繁的重新验证)。允许您仅使用客户端代码刷新特定图像,而无需更改当前页面或任何其他页面上该图像的URL。

缺点:依靠Javascript。并非100%保证在每种浏览器中都能正常工作(尽管我已经在FF27,Chrome33和IE11中成功测试了此功能)。相对于其他方法而言非常复杂。

何时使用:当您要缓存一些基本静态的图像时,您仍然需要偶尔进行更新,并获得更新发生后的即时视觉反馈。(尤其是在仅刷新整个浏览器页面时,如在基于AJAX的某些Web应用程序中那样无法工作)。当方法(1)-(3)不可行时,因为(由于某种原因)您不能更改所有可能显示需要更新的图像的URL。(请注意,使用这三种方法将刷新图像,但是如果使用其他方法页面尝试显示该图像而没有适当的查询字符串或片段标识符,则可能会显示旧版本)。

下面给出了以一种强大而灵活的方式实现此操作的详细信息:

假设您的网站在URL路径中包含一个空白的1x1像素.gif /img/1x1blank.gif,并且还具有以下单行PHP脚本(仅对跨域图像应用强制刷新才需要,并且可以用任何服务器端脚本语言进行重写,当然)在URL路径/echoimg.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数组[成功,宽度,高度],那么您的代码可能看起来像这样:

// 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进行一些更改。


我喜欢方法4的想法,但是您无法使用iframe加载外部内容,可以吗?我当前在单页Web应用程序中使用方法3,但我不喜欢必须重新加载整个页面才能获得新图像的事实,即使重新加载了模板的HTML也是如此。
Emilios1995

@Emilios:...此外,我不理解您对必须重新加载整个页面的评论。方法(3)和(4)均可在客户端javascript中实现,而无需重新加载除您要刷新的一个图像以外的任何内容。对于方法(3),这仅意味着使用javascript将图像的'src'属性从(例如)image.jpg#123更改为image.jpg#124(或其他任何东西,只要'#'之后的位发生变化)。您能否说明您要重新加载什么,为什么?
Doin 2015年

@Emilios:您确实可以将外部(跨域)内容加载到iframe中……但您随后无法contentWindow通过javascript进行访问,这是reload(true)方法的关键部分……所以,方法(4 )不适用于跨域内容。好眼力; 我将更新“缺点”以包括该内容。
Doin 2015年

@Emilios:糟糕,不,我不会:我意识到,一个简单的修复程序(现在已包含在我的答案中)也可以使其适用于跨域图像(前提是您可以在服务器上放置服务器端脚本)。
2015年

@pseudosavant:不幸的是,我仅在大约17个月后才注意到这一点,但是很抱歉不得不告诉您,您对我的代码所做的编辑严重中断。(公平地说,我也不认为我最初使用的回调代码是正确的)。我现在已经广泛地重写了第(4)部分,包括解释和代码。您以前的代码从未使图像空白(因此,它可能会以奇怪的方式失败,尤其是在IE中,尤其是如果图像在多个位置显示),但更糟糕的是,它在开始完全重新加载后也立即删除了iframe,这可能意味着只能间歇性地工作或根本不工作。抱歉!
Doin

185

作为...的替代

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,否则它无法在Safari上运行...

Cache-Control: no-store

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

更新(2014-09-28):如今看来Cache-Control: no-store,Chrome也同样需要。


1
大!经过大量时间尝试加载延迟加载的网络图像后,我刚刚通过应用您的解决方案(使用“#”,使用“?”对我不起作用)解决了它。非常感谢!!!
user304602

18
这里涉及两个缓存:有浏览器的常规HTTP缓存,以及最近显示的图像的内存中缓存。后者的内存中高速缓存由full src属性索引,因此添加唯一的片段标识符可确保不会简单地从内存中提取图像。但是片段标识符不会作为HTTP请求的一部分发送,因此常规HTTP缓存将正常使用。这就是为什么这种技术行之有效的原因。
Doin 2014年

有几个头缓存。实际上我不太会英语,您能告诉我我应该使用哪一种吗?我想要的东西不仅要缓存更改过的照片(例如验证码),还要缓存其他东西。这样Cache-Control: max-age=0, must-revalidate是为我好?
Shafizadeh,2015年

它对我不起作用。在我的情况下,唯一不同的是我有一个控制器操作的URL,该操作从数据库检索img。我还有其他用于控制器操作的参数,因此我将其添加为“ ......&convert = true&t =“ + new Date()。getTime();)。和“ ......&convert = true#” +新的Date()。getTime();。我做错了什么吗?
shaffooo

1
为了避免对象创建和/​​或方法调用的开销,您可以使用递增整数作为缓存无效项:newImage.src = "http://localhost/image.jpg#" + i++;
laindir

7

创建新映像后,您是否要从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);
}

完成该工作后,如果仍然存在问题,则可能是缓存问题,就像其他答案所讨论的那样。


3

一种解决方法是像建议的那样随意添加一些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中添加,并且must-revalidate标记指示即使在恶劣的情况下,代理也不应提供旧映像,这Pragma: no-cache对于当前的现代浏览器/缓存不是必需的,但可以帮助解决一些笨拙的旧实现。


3
这听起来像是可行的,但即使有骇客,它仍然显示相同的图像。我将标题信息添加到问题中。
QueueHammer

我只是注意到您不断刷新相同的img标签。浏览器可能会检测到何时设置src时未更改src,因此不会刷新。(由于此检查是在DOM级别进行的,因此与目标无关)。如果添加“?”会怎样?+数字-要检索的图像的URL?
爱德华·KMETT 09年

3

我有一个要求: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。


3
<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秒内重新加载图像。我在带有各种类型的家庭安全摄像机的页面上使用此功能。


2

我最终要做的是让服务器将该目录下的任何图像请求映射到我尝试更新的源。然后,我让我的计时器在名称的末尾附加一个数字,以便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);
}

8
与查询字符串解决方案(Paolo和其他一些解决方案)一样,缓存图像的多个副本将具有相同的问题,并且需要更改服务器。
TomG 2012年

2

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')" />


3
请向OP解释这样做的方式和原因,而不仅仅是粘贴代码
-nomistic

我认为这不是../showImage.phpFri May 01 2015 17:34:18 GMT+0200 (Mitteleuropäische Sommerzeit)有效的文件名...至少这是它试图加载的内容...
ByteHamster,2015年

更改path='../showImage.php';path='../showImage.php?';
BOOMik

2
document.getElementById("img-id").src = document.getElementById("img-id").src

将自己的src设置为其src。


1

尝试使用毫无价值的查询字符串,使其成为唯一的网址:

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

在代码中添加了WQS,并验证了请求已被接受,并且浏览器将响应视为来自地址+ WQS,而没有刷新图像。
QueueHammer

1

以下示例以Doin的#4代码为基础,大大简化了该代码,document.write而无需src 使用iframe来支持CORS。还只专注于清除浏览器缓存,而不是重新加载页面上的每个图像。

下面是typescript使用angular $ q promise库编写的,只是fyi,但应该足够容易地移植到原始javascript。方法应该存在于打字稿类中。

返回一个承诺,当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;
    }

为了防止你应该使用XSS漏洞+ encodeURI(src) +来逃避正常srciframe
蒂诺

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')" />

不赞成投票。由于它只是@Mahmoud的代码的略微修改的副本,但是相比之下,这里并没有刷新图像
Tino

0

我通过将数据发送回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">

0

这是我的解决方案。非常简单 帧调度可能会更好。

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

0

不需要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>

0

简单的解决方案:将此标头添加到响应中:

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中使用#的片段不起作用,因为#告诉浏览器不要向服务器发送请求。

可以在网址中添加随机部分的缓存无效化工具,但也会填充浏览器缓存。在我的应用程序中,我想每隔几秒钟从网络摄像头下载5 MB的图片。完全冻结您的PC只需要一个小时或更短的时间。我仍然不知道为什么浏览器缓存不限于合理的最大值,但这绝对是一个缺点。


0

我改进了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>

-3

我使用以下概念,首先将图像与一个假(缓冲区)URL绑定,然后再将其与有效URL绑定。

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

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

这样,我强迫浏览器使用有效的URL刷新。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.