同じ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
また、後で「キャッシュブレーカー」なしで同じ画像を別の場所に再表示しても、古いキャッシュバージョン(少なくともFirefoxでは)が両方表示されますか?および#:(
T4NK3R

3
これでさらに少ないコードを作成できます:'image.jpg?' + (+new Date())
Lev Lukomsky

4
ありDate.now()、このために
vp_arth

2
なぜMath.random()
Gowtham Gopalakrishnan 2017

227

私はこれを行う方法の答えに多くのバリエーションを見たので、ここでそれらを要約すると思います(さらに、自分の発明の4番目の方法を追加します)。


(1)次のような一意のキャッシュ無効化クエリパラメータをURLに追加します。

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

長所: 100%信頼性が高く、すばやく簡単に理解して実装できます。

短所:キャッシングを完全にバイパスします。つまり、画像ビュー間で変化しない場合は常に、不必要な遅延と帯域幅の使用を意味します。ブラウザーキャッシュ(および中間キャッシュ)を、まったく同じ画像の多数のコピーで潜在的に埋めます。また、画像のURLを変更する必要があります。

使用する場合ライブWebカメラフィードなど、画像が常に変化する場合に使用します。この方法を使用する場合は、必ずCache-control: no-cacheHTTPヘッダーを使用して画像自体を提供してください!!! (多くの場合、これは.htaccessファイルを使用して設定できます)。そうしないと、古いバージョンのイメージでキャッシュが徐々にいっぱいになります。


(2)ファイルが変更された場合にのみ変更されるクエリパラメータをURLに追加します。例:

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

(これはPHPサーバー側のコードですが、ここで重要な点は、?m = [ファイルの最終変更時刻]クエリ文字列がファイル名に追加されることです)。

長所:理解し、実装が迅速&簡単に、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#Bimage.jpg#Aが最後に表示されたときからのメモリ内保持画像データを使用して表示されることはありません)。

長所: HTTPキャッシュメカニズムを適切に使用し、変更されていない場合はキャッシュされた画像を使用します。静的画像URLに追加されたクエリ文字列を制限するサーバーで機能します(サーバーはフラグメント識別子を決して見ないため、ブラウザーの使用のみを目的としています)。

短所: URLにフラグメント識別子が含まれている画像に関して、ブラウザーのやや怪しげな(または少なくとも十分に文書化されていない)動作に依存します(ただし、FF27、Chrome33、およびIE11でこれをうまくテストしました)。すべての画像ビューに対してサーバーに再検証リクエストを送信しますが、画像がめったに変更されない場合やレイテンシが大きな問題である場合は、やり過ぎになる可能性があります(キャッシュされた画像がまだ良好な場合でも再検証応答を待つ必要があるため) 。画像のURLを変更する必要があります。

使用する場合画像が頻繁に変更される可能性がある場合、またはサーバー側のスクリプトを使用せずにクライアントによって断続的に更新する必要があるが、キャッシュの利点を引き続き必要とする場合に使用します。たとえば、数分ごとに不規則に画像を更新するライブWebカメラをポーリングします。または、サーバーが静的画像のURLでクエリ文字列を許可しない場合は、(1)または(2)の代わりに使用します。


(4)JavaScriptを使用して特定の画像を強制的に更新します。最初に画像を非表示にロードしてから、iframeを<iframe>呼び出します。location.reload(true)contentWindow

手順は次のとおりです。

  • 更新する画像を非表示のiframeに読み込みます。これは単なるセットアップ手順です。必要に応じて、実際の更新のかなり前に行うことができます。この段階で画像の読み込みに失敗しても問題ありません。

  • それが完了したら、ページまたはDOMノードの任意の場所(JavaScript変数に保存されているページ外のものも含む)でその画像のすべてのコピーを空白にします。これは、ブラウザーが古いメモリ内コピーからの画像を表示する可能性があるために必要です(IE11は特にこれを行います)。HTTPキャッシュを更新する前に、すべてのメモリ内コピーがクリアさていることを確認する必要があります。他のJavaScriptコードが非同期で実行されている場合は、そのコードがその間に更新されるイメージの新しいコピーを作成しないようにする必要がある場合もあります。

  • を呼び出しiframe.contentWindow.location.reload(true)ます。はtrue強制的にキャッシュをバイパスし、サーバーから直接リロードして、既存のキャッシュされたコピーを上書きします。

  • 読み込みが完了したら、非表示の画像を復元します。これで、サーバーからの最新バージョンが表示されます。

同じドメインの画像の場合、画像を直接iframeに読み込むことができます。クロスドメイン画像の場合は、代わりにタグ内の画像を含むドメインから HTMLページロードする<img>必要があります。そうしないと、を呼び出そうとすると「アクセス拒否」エラーが発生しますiframe.contentWindow.reload(...)

長所:ちょうどあなたがimage.reload()関数のように動作したい DOMを持っていました!画像を通常どおりにキャッシュできるようにします(必要に応じて、将来の有効期限があっても、頻繁な再検証を回避できます)。クライアント側のコードのみを使用して、現在のページまたは他のページにある画像のURLを変更せずに、特定の画像を更新できます。

短所: Javascriptに依存しています。すべてのブラウザーで正しく動作することが100%保証されているわけではありません(ただし、FF27、Chrome33、およびIE11でこれを正常にテストしました)。他の方法に比べて非常に複雑です。

使用するタイミング:キャッシュしたい基本的に静的な画像のコレクションがあるが、それらを時々更新して、更新が行われたことを即座に視覚的にフィードバックできるようにする必要がある場合。(特に、たとえばAJAXで構築された一部のWebアプリのように、ブラウザーページ全体を更新するだけでは機能しません)。また、メソッド(1)〜(3)が実行できない場合は、(何らかの理由で)更新が必要な画像を表示する可能性のあるすべてのURLを変更できないためです。(これらの3つの方法を使用すると、画像が更新されますが、別のページが適切なクエリ文字列またはフラグメント識別子なしでその画像を表示しようとすると、代わりに古いバージョンが表示される場合があります)。

これをかなり堅牢で柔軟な方法で実装する詳細を以下に示します。

WebサイトのURLパス/img/1x1blank.gifに空白の1x1ピクセルの.gif があり、次の1行のPHPスクリプトがあると仮定します(クロスドメイン画像に強制更新を適用する場合にのみ必要で、サーバー側のスクリプト言語で書き換えることができます) 、もちろん)URLパス/echoimg.php

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

次に、JavaScriptでこれを行う方法の現実的な実装を示します。少し複雑に見えますが、コメントがたくさんあり、重要な関数はforceImgReload()です-最初の2つは空白と空白以外の画像であり、独自の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 2015

@エミリオス:...また、ページ全体をリロードする必要があるというコメントも理解できません。(3)と(4)の両方の方法は、クライアント側のJavaScriptで実装でき、更新する1つの画像以外は何も再ロードしません。メソッド(3)の場合は、JavaScriptを使用して画像の「src」プロパティを(たとえば)image.jpg#123からimage.jpg#124(または、「#」が変更された後のビットであれば何でも)に変更することを意味します。何をリロードするのか、そしてその理由を明確にしていただけますか?
Doin

@Emilios:実際に外部(クロスドメイン)コンテンツをiframeにロードできます...しかし、その後、contentWindowJavaScriptを介してコンテンツにアクセスしてreload(true)、メソッドの重要な部分である呼び出しを実行することはできません...したがって、メソッド(4 )クロスドメインコンテンツでは機能しません。よく発見されました。それを含むように「短所」を更新します。
Doin

@エミリオス:おっと、私はしません:簡単な修正(今は私の回答に含まれています)により、クロスドメインイメージでも機能することがわかりました(サーバー側のスクリプトをサーバーに配置できる場合)。
Doin、2015

@pseudosavant:残念ながら、これはたったの17か月後のことですが、申し訳ありませんが、私のコードへの編集が大幅に壊れていました。(公平を期すために、私が最初に持っていたコールバックコードも正しくなかったと思います)。説明とコードの両方で、パート(4)を大幅に書き直しました。以前のコードでは画像が空白になることはありませんでした(そのため、特にIEで、特に画像が複数の場所に表示された場合に、奇妙な方法で失敗する可能性がありました)。断続的にのみ動作するか、まったく動作しない。ごめんなさい!
Doin、2015

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-store、Chromeにも必要なようです。


1
すごい!遅延して読み込まれていたWeb画像を何度も読み込もうとした後、ソリューションを適用して解決しました( '#'を使用し、 '?'を使用しても機能しません)。どうもありがとう!!!
user304602 2013年

18
ここには2つのキャッシュがあります。ブラウザの通常のHTTPキャッシュと、最近表示された画像のメモリ内キャッシュです。この後者のメモリ内キャッシュは、完全なsrc属性によってインデックスが付けられるため、一意のフラグメント識別子を追加することで、イメージがメモリから単純にプルされるだけではありません。ただし、フラグメント識別子はHTTPリクエストの一部として送信されないため、通常のHTTPキャッシュが通常どおり使用されます。これが、この手法が機能する理由です。
Doin

いくつかのヘッダーキャッシュがあります。実は英語があまりわからないので、どれを使うべきか教えていただけませんか?変更された写真だけをキャッシュしないもの(CAPTCHAなど)と、その他のものをキャッシュする必要があります。だからCache-Control: max-age=0, must-revalidate私にいいの?
Shafizadeh

私にはうまくいきません。私の場合の唯一の違いは、dbからimgを取得するコントローラーアクションへのURLがあることです。コントローラーアクションには他の引数があったため、「......&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

1つの答えは、提案されているような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。must-revalidate タグは、状況が悪化した場合でもプロキシが古いイメージを提供してはならないことを示します。これは、現在の最新のブラウザ/キャッシュでは実際には必要ありませんが、一部の壊れた古い実装では役立つ場合があります。


3
これはうまくいくように聞こえましたが、ハックを使っても同じ画像が表示されます。質問にヘッダー情報を追加します。
QueueHammer 2009

同じimgタグを何度も更新していることに気づきました。ブラウザーは、srcを変更するときに、srcが変更されていないことを検出している可能性があるため、更新する必要はありません。(このチェックはDOMレベルで行われ、ターゲットとは関係がないため)。「?」を追加するとどうなりますか?+番号-取得する画像のURLに?
エドワードKMETT 2009

3

私は要件を持っていました:1)?var=xx画像に何も追加できません2)クロスドメインで動作するはずです

私は本当に#4でオプションのようなこの回答 1ではなく:

  • クロスドメインを確実に操作するのに問題があります(サーバーコードに触れる必要があります)。

私の速くて汚い方法は:

  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、

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

変更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 2009

1

以下の例は、Doinの#4コードに大きく基づいて おり、CORSをサポートするためdocument.writesrcではなく、コードを非常に活用してコードを簡素化していますiframe。また、ページのすべての画像をリロードするのではなく、ブラウザキャッシュの破壊にのみ焦点を当てています。

以下は記述されtypescriptており、$ qを使用しますangular fyiで promiseライブラリていますが、バニラJavaScriptに移植するのに十分簡単なはずです。メソッドは、typescriptクラス内に存在することを意図しています。

iframeの再読み込みが完了したときに解決されるpromiseを返します。十分にテストされていませんが、私たちにはうまく機能します。

    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ます。
ティノ

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()厄介者は必要ありません。非表示のダミー画像を用意し、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に追加されたキャッシュバスターは機能しますが、ブラウザーのキャッシュも満たします。私のアプリでは、Webカメラから数秒ごとに5 MBの画像をダウンロードしたいと思っていました。お使いのPCを完全に凍結するには、わずか1時間かかかりません。ブラウザーのキャッシュが妥当な最大値に制限されていない理由はまだわかりませんが、これは明らかに欠点です。


0

AlexMAのスクリプトを改善して、同じ名前の新しい画像を定期的にアップロードするWebページにWebカメラを表示するようにしました。画像が壊れている、または完全な(アップロードされた)画像が原因で画像がちらつくことがあるという問題がありました。ちらつきを防ぐために、ウェブカメラ画像のサイズは変更されなかったため、画像の自然な高さを確認します。ロードされた画像の高さが元の画像の高さに適合する場合のみ、画像全体がページに表示されます。

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