동일한 URL에서 새 이미지로 이미지 새로 고침


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

페이지에서 해당 이미지 만 새로 고침해야합니다. 어떤 아이디어?


답변:


350

URL 끝에 캐시 차단기를 추가하십시오.

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

이렇게하면 이미지를 만들 때 현재 타임 스탬프가 자동으로 추가되며 캐시에서 이미지를 검색하는 대신 브라우저에서 이미지를 다시 찾습니다.


26
캐시를 늪지대 (로컬 및 업스트림 모두)로 사용하는 것은 좋지 않습니다. 아야의 대답 은 이것을 다루는 더 좋은 방법입니다.
Tgr

1
또한 나중에 "캐시 브레이커"없이 동일한 이미지를 다른 곳에 다시 표시해도 이전 캐시 된 버전 (적어도 파이어 폭스에서는)이 둘 다 표시됩니까? 그리고 # :(
T4NK3R

3
:이와 더 적은 코드를 만들 수 있습니다'image.jpg?' + (+new Date())
레프 Lukomsky

4
Date.now()이것에 대한
vp_arth

2
왜 안돼Math.random()
Gowtham Gopalakrishnan

227

이 작업을 수행하는 방법에 대한 답변에서 많은 변형을 보았으므로 여기에 요약 할 것이라고 생각했습니다 (내 자신의 발명품의 네 번째 방법을 추가하십시오).


(1) 고유 한 캐시 버스 팅 쿼리 매개 변수를 URL에 다음과 같이 추가하십시오.

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

장점 : 100 % 신뢰성, 빠르고 이해하기 쉽고 구현하기

단점 : 캐싱을 모두 우회하므로 이미지 뷰간에 변경 되지 않을 때마다 불필요한 지연 및 대역폭 사용을 의미 합니다. 정확히 동일한 이미지의 많은 사본으로 브라우저 캐시 및 중간 캐시를 채울 수 있습니다! 또한 이미지 URL을 수정해야합니다.

사용시기 : 라이브 웹캠 피드와 같이 이미지가 계속 변경 될 때 사용합니다. 이 방법을 사용하는 경우 HTTP 헤더로 이미지 자체를 제공해야합니다 Cache-control: no-cache!!! (종종 .htaccess 파일을 사용하여 설정할 수 있습니다). 그렇지 않으면 이전 버전의 이미지로 캐시를 점진적으로 채 웁니다!


(2) 파일이 변경 될 때만 변경되는 URL에 쿼리 매개 변수를 추가합니다 (예 :

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

(PHP 서버 측 코드이지만 여기서 중요한 점은? m = [file last-modified time] 쿼리 문자열이 파일 이름에 추가된다는 것입니다).

장점 : 100 % 신뢰성, 빠르고 이해하기 쉽고 구현 캐싱 이점을 완벽하게 유지합니다.

단점 : 이미지 URL을 수정해야합니다. 또한 서버에 대한 약간의 작업-파일 마지막 수정 시간에 액세스해야합니다. 또한 서버 측 정보가 필요하므로 새로 고친 이미지를 확인하기위한 순수한 클라이언트 측 솔루션에는 적합하지 않습니다.

사용시기 : 이미지를 캐시하고 싶지만 파일 이름 자체를 변경하지 않고 때때로 서버 끝에서 이미지를 업데이트해야 할 수 있습니다. 그리고 올바른 쿼리 문자열이 HTML의 모든 이미지 인스턴스에 추가되는지 쉽게 확인할 수 있습니다.


(3) 헤더를 사용하여 이미지를 제공 Cache-control: max-age=0, must-revalidate하고 고유 한 memcache -busting 조각 식별자를 URL에 다음과 같이 추가하십시오.

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

여기서의 아이디어는 캐시 제어 헤더가 이미지를 브라우저 캐시에 넣지 만 즉시 이미지를 오래된 것으로 표시하여 다시 표시 될 때마다 브라우저가 서버와 함께 변경되었는지 확인해야한다는 것입니다. 이렇게하면 브라우저의 HTTP 캐시가 항상 최신 이미지 사본을 리턴합니다. 그러나 브라우저는 이미지가있는 경우 메모리 내 이미지 사본을 재사용하고,이 경우 HTTP 캐시를 확인하지 않는 경우가 종종 있습니다. 이를 방지하기 위해 프래그먼트 식별자가 사용됩니다. 메모리 내 이미지 비교에는 프래그먼트 식별자가 src포함되지만 HTTP 캐시를 쿼리하기 전에 제거됩니다. (그래서, 예를 들면, image.jpg#A그리고 image.jpg#B모두에서 표시 될 수 image.jpg있는 항목 브라우저의 HTTP 캐시하지만,image.jpg#B( image.jpg#A마지막으로 표시 되었을 때의 메모리 내장 이미지 데이터를 사용하여 표시되지 않습니다).

장점 : HTTP 캐싱 메커니즘을 올바르게 사용하고 변경되지 않은 경우 캐시 된 이미지를 사용합니다. 정적 이미지 URL에 추가 된 쿼리 문자열을 질식하는 서버에서 작동합니다 (서버는 조각 식별자를 볼 수 없으므로 브라우저 전용입니다).

단점 : URL에 조각 식별자가있는 이미지와 관련하여 브라우저의 다소 모호한 (또는 적어도 문서화가 잘되지 않은) 동작에 의존합니다 (그러나 나는 이것을 FF27, Chrome33 및 IE11에서 성공적으로 테스트했습니다). 모든 이미지보기에 대해 서버에 유효성 다시 확인 요청을 계속 보냅니다. 이미지가 거의 변경되지 않거나 지연 시간이 큰 문제인 경우 너무 많은 문제가 발생할 수 있습니다 (캐시 된 이미지가 여전히 양호한 경우에도 다시 확인 응답을 기다려야하기 때문에) . 이미지 URL을 수정해야합니다.

사용시기 : 이미지가 자주 변경되거나 서버 측 스크립트를 사용하지 않고 클라이언트가 간헐적으로 새로 고쳐야하지만 캐싱의 이점이 필요한 경우에 사용합니다. 예를 들어, 몇 분마다 이미지가 불규칙적으로 업데이트되는 라이브 웹캠을 폴링합니다. 또는 서버가 정적 이미지 URL에서 쿼리 문자열을 허용하지 않는 경우 (1) 또는 (2) 대신 사용하십시오.


(4) 숨겨진 이미지를 먼저로드 <iframe>한 다음 location.reload(true)iframe 을 호출 하여 Javascript를 사용하여 특정 이미지를 강제로 새로 고칩니다 contentWindow.

단계는 다음과 같습니다.

  • 숨겨진 iframe에 새로 고칠 이미지를로드하십시오. 이것은 설정 단계 일뿐입니다. 원하는 경우 실제 새로 고침을 오래 전에 수행 할 수 있습니다. 이 단계에서 이미지가로드되지 않더라도 중요하지 않습니다!

  • 이 작업이 완료되면 페이지 또는 DOM 노드의 모든 위치 (자바 스크립트 변수에 저장된 페이지 외부 페이지에서도)에서 해당 이미지의 모든 사본을 비 웁니다. 브라우저가 오래된 메모리 내 사본의 이미지를 다르게 표시 할 수 있기 때문에이 작업이 필요합니다 (IE11이 특히 그러합니다) : HTTP 캐시를 새로 고치기 전에 모든 메모리 내 사본이 지워 졌는지 확인해야 합니다. 다른 자바 스크립트 코드가 비동기 적으로 실행중인 경우 해당 코드가 새로 고침 될 이미지의 새 사본을 작성하지 못하게 할 수도 있습니다.

  • 전화하십시오 iframe.contentWindow.location.reload(true). true힘 캐시 우회 서버에서 직접 다시로드하고 기존의 캐시 된 복사본을 덮어 씁니다.

  • 다시로드 가 완료되면 빈 이미지를 복원하십시오. 이제 서버에서 최신 버전을 표시해야합니다!

동일한 도메인 이미지의 경우 이미지를 iframe에 직접로드 할 수 있습니다. 도메인 간 이미지의 경우 대신 이미지를 태그 에 포함 하는 HTML 페이지 를 도메인에서 로드 해야합니다<img> . 그렇지 않으면을 호출 할 때 "액세스 거부"오류가 발생합니다 iframe.contentWindow.reload(...).

장점 : DOM에 원하는 image.reload () 함수와 동일하게 작동합니다 ! 이미지를 정상적으로 캐시 할 수 있습니다 (원하는 경우 미래의 만료일이 있더라도 재확인을 자주하지 않아도 됨). 클라이언트 쪽 코드 만 사용하여 현재 페이지 또는 다른 페이지에서 해당 이미지의 URL을 변경하지 않고 특정 이미지를 새로 고칠 수 있습니다.

단점 : 자바 스크립트를 사용합니다. 모든 브라우저에서 100 % 제대로 작동하는 것은 아닙니다 (FF27, Chrome33 및 IE11에서 성공적으로 테스트했습니다). 다른 방법에 비해 매우 복잡합니다.

사용시기 : 캐시하려는 기본적으로 정적 이미지 모음이 있지만 여전히 업데이트 할 수 있어야하며 업데이트가 발생한 즉시 시각적 인 피드백을 받아야합니다. (특히 AJAX를 기반으로 구축 된 일부 웹 앱에서와 같이 전체 브라우저 페이지를 새로 고치면 작동하지 않습니다.) 그리고 어떤 이유로 든 메소드 (1)-(3)을 실행할 수없는 경우 업데이트해야 할 이미지를 표시 할 수있는 모든 URL을 변경할 수 없습니다. (이 3 가지 방법을 사용하면 이미지가 새로 고쳐 지지만 다른 페이지 에서 적절한 쿼리 문자열이나 조각 식별자 없이 해당 이미지를 표시하려고 하면 이전 버전이 표시 될 수 있습니다).

공정하고 견고하고 유연한 방법으로이를 구현하는 세부 사항은 다음과 같습니다.

웹 사이트에 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)에서 위의 자바 스크립트를 일부 변경해야 할 수도 있습니다.


방법 4의 아이디어가 마음에 들지만 Iframe으로 외부 콘텐츠를로드 할 수 없습니까? 현재 단일 페이지 웹 앱에서 방법 3을 사용하고 있지만 템플릿의 HTML을 다시로드하더라도 새 이미지를 얻으려면 전체 페이지를 다시로드해야한다는 사실이 마음에 들지 않습니다.
Emilios1995

@Emilios : ... 또한 전체 페이지를 다시로드해야한다는 의견을 이해하지 못합니다. 메소드 (3) 및 (4)는 새로 고치는 하나의 이미지를 제외한 다른 것을 다시로드하지 않고 클라이언트 측 자바 스크립트로 구현할 수 있습니다. 방법 (3)의 경우 자바 스크립트를 사용하여 이미지의 'src'속성을 (예) image.jpg#123에서 image.jpg#124(또는 '#'뒤의 비트가 변경되는 한 무엇이든) 변경하는 것을 의미합니다. 다시로드하고있는 것이 무엇인지, 왜 그 이유를 알 수 있습니까?
Doin

@Emilios : 실제로 외부 (크로스 도메인) 내용을 iframe에로드 할 수는 있지만 contentWindow자바 스크립트를 통해 액세스 reload(true)하여 메소드의 중요한 부분 인 호출 을 수행 할 수는 없습니다. )는 도메인 간 콘텐츠에서 작동하지 않습니다. 잘 발견했다. 이를 포함하도록 "Cons"를 업데이트하겠습니다.
Doin

@Emilios : 죄송합니다. 아닙니다. : 간단한 수정 (현재 답변에 포함되어 있음)을 통해 도메인 간 이미지에서도 작동 할 수 있음을 알게되었습니다 (서버 측 스크립트를 서버에 배치 할 수있는 경우).
Doin

@ 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-Since또는 If-None-Match헤더 의 이점을 잃어 버리므로 ...

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

... 실제로 이미지가 변경되지 않은 경우 브라우저가 전체 이미지를 다시 다운로드하지 못하게해야합니다. IE, Firefox 및 Chrome에서 테스트하고 작업했습니다. 짜증나게 사용하지 않으면 Safari에서 실패합니다 ...

Cache-Control: no-store

... 이것은 여전히 ​​수백 개의 동일한 이미지로 업스트림 캐시를 채우는 것보다, 특히 자신의 서버에서 실행될 때 바람직 할 수 있습니다. ;-)

업데이트 (2014-09-28) : 요즘 Cache-Control: no-storeChrome에도 필요한 것 같습니다 .


1
큰! 많은 시간이 지연되어로드 된 웹 이미지를로드하려고 시도한 후 솔루션을 적용하여 해결했습니다 ( '#', '?'를 사용하면 작동하지 않습니다). 많은 감사합니다 !!!
user304602

18
여기에는 두 개의 캐시가 있습니다. 브라우저의 일반 HTTP 캐시와 최근에 표시 한 이미지의 메모리 내 캐시가 있습니다. 후자의 메모리 내 캐시는 전체 src속성으로 색인화 되므로 고유 한 조각 식별자를 추가하면 이미지가 단순히 메모리에서 가져 오지 않습니다. 그러나 조각 식별자는 HTTP 요청의 일부로 전송되지 않으므로 일반 HTTP 캐시가 정상적으로 사용됩니다. 이것이이 기술이 작동하는 이유입니다.
Doin

여러 개의 헤더 캐시가 있습니다. 실제로 나는 영어를 잘 몰라요, 어느 것을 사용해야하는지 말씀해 주시겠습니까?! 변경 된 사진 (보안 문자처럼)을 캐시하지 않고 다른 것을 캐시하지 않는 것을 원합니다. 그래서 Cache-Control: max-age=0, must-revalidate나를 위해 좋은?
Shafizadeh

그것은 나를 위해 작동하지 않습니다. 내 경우에는 다른 점은 db에서 img를 검색하는 컨트롤러 작업에 대한 URL이 있다는 것입니다. 컨트롤러 작업에 대한 다른 인수가 있으므로 "...... & convert = true & t ="+ new Date (). getTime (); 및 "...... & convert = true #"+ new 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-ControlHTTP / 1.1에 추가되었으며 must-revalidate 태그는 프록시가 소멸되는 환경에서도 오래된 이미지를 제공해서는 안되며 Pragma: no-cache현재 최신 브라우저 / 캐시에는 실제로 필요하지는 않지만 이전에 구현 된 일부 구현에 도움이 될 수 있음을 나타냅니다.


3
이것은 작동하는 것처럼 들리지만 해킹에서도 여전히 동일한 이미지를 보여줍니다. 질문에 헤더 정보를 추가하겠습니다.
QueueHammer

방금 동일한 img 태그를 새로 고침하고 있음을 알았습니다. 브라우저는 src가 변경되지 않은 src를 설정하려고 할 때 감지하므로 새로 고침하지 않아도됩니다. (이 점검은 DOM 레벨에서 발생하므로 대상과 아무 관련이 없습니다). ""를 추가하면 어떻게됩니까? + 숫자-검색되는 이미지의 URL?
Edward KMETT

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 이벤트로 변경해야합니다.


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

그런 다음 일부 자바 스크립트에서

<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

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
영업 이익에 대해 설명 어떻게 그리고 왜이 대신 코드를 붙여의 도움 바랍니다
nomistic

나는 그것이 ../showImage.phpFri May 01 2015 17:34:18 GMT+0200 (Mitteleuropäische Sommerzeit)유효한 파일 이름 이라고 생각하지 않습니다 ... 적어도 이것이로드하려고하는 것입니다 ...
ByteHamster

변화 path='../showImage.php';path='../showImage.php?';
BOOMik

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

자체 src를 src로 설정하십시오.


1

쓸모없는 쿼리 문자열을 사용하여 고유 한 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);
}

코드에 WQS를 추가하고 요청이 수락되고 브라우저가 이미지를 새로 고치지 않고 주소 + WQS에서 오는 것으로 응답을 확인하는지 확인했습니다.
QueueHammer

1

심하게 하긴의 # 4 코드를 기반으로, 예 아래의 단순화 코드 좋은 비트를 사용하는 것을 document.write대신 src 에 iframeCORS를 지원합니다. 또한 페이지의 모든 이미지를 다시로드하지 않고 브라우저 캐시 버스 팅에만 중점을 둡니다.

아래는 $ q promise 라이브러리를 typescript사용하여 작성 되었지만 바닐라 자바 ​​스크립트로 이식하기에 충분히 쉬워야합니다. 메서드는 typescript 클래스 안에 있어야합니다.angular

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) +를 올바르게 탈출 하는 데 사용해야 src합니다 iframe.
Tino

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

서블릿을 통해 데이터를 다시 보내서이 문제를 해결했습니다.

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

그런 다음 페이지에서 올바른 이미지 파일을 얻을 수있는 매개 변수가있는 서블릿을 제공합니다.

<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()shenanigans 필요가 없습니다 . 보이지 않는 더미 이미지가 있고 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에서 #을 사용하는 조각은 작동하지 않습니다.

URL에 임의의 부분이 추가 된 캐시 버스터는 작동하지만 브라우저 캐시도 채 웁니다. 내 앱에서 웹 캠에서 몇 초마다 5MB 사진을 다운로드하고 싶었습니다. PC를 완전히 정지시키는 데 1 시간 정도 걸립니다. 브라우저 캐시가 합리적인 최대 값으로 제한되지 않는 이유는 여전히 모르겠지만 이는 분명히 단점입니다.


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

아래 이미지를 먼저 false (buffer) url로 바인딩하고 유효한 url로 바인딩하는 개념을 사용했습니다.

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

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

이렇게하면 브라우저가 유효한 URL로 새로 고쳐집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.