簡體   English   中英

如何清除或替換緩存的圖像

[英]how to clear or replace a cached image

我知道有很多方法可以防止圖像緩存(例如通過 META 標記),還有一些不錯的技巧可以確保每次頁面加載時都顯示圖像的當前版本(例如 image.jpg?x=timestamp ),但是有沒有辦法真正清除或替換瀏覽器緩存中的圖像,以便上述方法都不是必需的?

舉個例子,假設一個頁面上有 100 張圖像,這些圖像被命名為“01.jpg”、“02.jpg”、“03.jpg”等。如果圖像“42.jpg”被替換,是有什么方法可以在緩存中替換它,以便“42.jpg”在連續頁面加載時自動顯示新圖像? 我不能使用 META 標記方法,因為我需要替換 ISN"T 的所有內容以保持緩存,而且我不能使用時間戳方法,因為我不希望每次頁面都重新加載所有圖像負載。

我絞盡腦汁在互聯網上搜索了一種方法來做到這一點(最好通過javascript),但沒有運氣。 有什么建議?

如果您正在動態編寫頁面,則可以將最后修改的時間戳添加到 URL:

<img src="image.jpg?lastmod=12345678" ...

<meta>完全無關緊要。 事實上,您根本不應該嘗試使用它來控制緩存(當任何內容讀取文檔內容時,它已經被緩存了)。

在 HTTP 中,每個 URL 都是獨立的。 無論您對 HTML 文檔做什么,它都不適用於圖像。

要控制緩存,您可以在每次 URL 內容更改時更改 URL。 如果您不時更新圖像,請允許它們永久緩存並為新圖像使用新的文件名(帶有版本、哈希或日期)——這是長期文件的最佳解決方案。

如果您的圖像經常更改(每隔幾分鍾,甚至在每次請求時),則發送Cache-control: no-cacheCache-control: max-age= xx其中xx是圖像“新鮮”的秒數.

短期文件的隨機 URL 是個壞主意。 它會用無用的文件污染緩存,並強制更快地清除有用的文件。

如果您有 Apache 和mod_headersmod_expires則使用適當的規則創建.htaccess文件。

<Files ~ "-nocache\.jpg">
   Header set Cache-control "no-cache"
</Files>

以上將使*-nocache.jpg文件不可緩存。

您還可以通過 PHP 腳本提供圖像(默認情況下它們具有糟糕的可緩存性;)

相反的是一些其他的答案說,有一個客戶端JavaScript的方式來替換緩存圖像。 訣竅是創建一個隱藏的<iframe> ,將其src屬性設置為圖像 URL,等待它加載,然后通過調用location.reload(true)強制重新加載它。 這將更新圖像的緩存副本。 然后,您可以替換頁面上的<img>元素(或重新加載頁面)以查看圖像的更新版本。

(小警告:如果更新單個<img>元素,並且如果有多個更新的圖像,則必須將它們全部清除或刪除,然后替換或重置它們。如果您這樣做-一方面,一些瀏覽器會從其他標簽復制圖像的內存版本,結果是您可能看不到更新的圖像,盡管它在緩存中)。

我在這里發布了一些代碼來進行這種更新。

像這樣更改圖像 url,在查詢字符串中添加一個隨機字符串。

"image1.jpg?" + DateTime.Now.ToString("ddMMyyyyhhmmsstt");

我確信大多數瀏覽器都尊重Last-Modified HTTP 標頭。 將它們發送出去並請求新圖像。 如果 Last-Modified 行沒有改變,它將被瀏覽器緩存。

您可以在圖像上附加一個隨機數,就像給它一個新版本一樣。 我已經實現了類似的邏輯,並且運行良好。

<script>
var num = Math.random();
var imgSrc= "image.png?v="+num;
$(function() {
$('#imgID').attr("src", imgSrc);
})
</script>

使用 ?x=timestamp 技巧的原因是因為這是針對每個圖像執行此操作的唯一方法。 那個或動態生成圖像名稱並指向輸出圖像的應用程序。

我建議您弄清楚,服務器端,圖像是否已更改/更新,如果是,則使用 ?x=timestamp 技巧輸出您的標簽以強制新圖像。

不,沒有辦法強制刪除瀏覽器緩存中的文件,無論是通過 Web 服務器還是通過您可以放入它發送的文件中的任何內容。 瀏覽器緩存歸瀏覽器所有,由用戶控制。

因此,您應該將每個文件和每個 URL 視為應謹慎管理的寶貴資源。

因此,poroneL 對圖像文件進行版本控制的建議似乎是最好的長期答案。 ETAG 是在正常情況下使用的,但也許您的努力使其無效? 按照建議嘗試更改 ETAG。

更改圖像的 ETAG。

聽起來您的問題的基礎是如何從緩存中獲取舊版本的圖像。 我只是成功地進行了一次新調用並在標頭中指定不要從緩存中提取。 一旦你獲取它,你只是把它扔掉,但瀏覽器的緩存此時應該有更新的圖像。

    var headers = new Headers()
    headers.append('pragma', 'no-cache')
    headers.append('cache-control', 'no-cache')

    var init = {
      method: 'GET',
      headers: headers,
      mode: 'no-cors',
      cache: 'no-cache',
    }

    fetch(new Request('path/to.file'), init)

但是,重要的是要認識到這只會影響調用它的瀏覽器。 如果您希望在替換圖像后為任何瀏覽器提供新版本的文件,則需要通過服務器配置來完成。

這是使用 PHP 函數 filemtime() 的解決方案:

<?php 
     $addthis = filemtime('myimf.jpg');
?> 
<img src="myimg.jpg?"<?= $addthis;?> >

使用文件修改時間作為參數將導致它從緩存版本中讀取,直到文件發生更改。 這種方法比使用隨機數要好,因為如果文件沒有改變,緩存仍然可以工作。

我找到了這篇關於如何緩存任何文件的文章

在本文中有很多方法可以強制清除緩存,但這是我為我的圖像所做的方法:

fetch('/thing/stuck/in/cache', {method:'POST', credentials:'include'});

請參閱http://en.wikipedia.org/wiki/URI_scheme

請注意,您可以提供唯一的 username:password@ 組合作為 uri 域部分的前綴。 在我的實驗中,我發現將其與假 ID(或我假設的密碼)包含在一起會導致將資源視為唯一的 - 從而根據需要破壞緩存。

只需使用時間戳作為用戶名,據我所知,只要未打開身份驗證,服務器就會忽略 uri 的這一部分。

順便說一句 - 我也無法將上面的技巧與谷歌地圖標記圖標緩存問題一起使用,我在 ?param=timestamp 技巧起作用的地方遇到了問題,但導致了覆蓋消失的問題。 永遠無法弄清楚為什么會發生這種情況,但到目前為止使用這種方法效果很好。 我不確定的是,傳遞虛假憑據是否會對服務器性能產生任何不利影響。 如果有人知道我很想知道,因為我還沒有進行大批量生產。

請報告您的結果。

要替換圖片的緩存,您可以在服務器端存儲一些版本值,當您加載圖片時,只需發送此值而不是時間戳。 當您的圖像更改時,請更改其版本。

當不能更改圖像文件名時,請使用服務器端會話變量和 javascript window.location.reload()函數。 如下:

上傳完成后:

Session("reload") = "yes"

在 page_load 上:

If Session("reload") = "yes" Then
    Session("reload") = Nothing
    ClientScript.RegisterStartupScript(Me.GetType), "ReloadImages", "window.location.reload();", True)
End If

這允許客戶端瀏覽器僅刷新一次,因為會話變量在一次發生后被重置。

希望這可以幫助。

如果圖像被重新上傳,有沒有辦法清除或替換以前緩存的圖像客戶端? 在我上面的例子中,目標是讓瀏覽器忘記“42.jpg”是什么

你在運行 Firefox 對嗎?

  • 找到Tools菜單
  • 選擇Clear Private Data
  • 取消選中所有復選框,但確保選中Cache
  • 按確定

:-)

嚴肅地說,我從來沒有聽說過這樣的東西存在,我懷疑是否有一個 API。 我無法想象讓瀏覽器開發人員在他們的緩存中四處閑逛會是一個好主意,而且我看不出他們有任何動機來實現這樣的功能。

我不能使用 META 標記方法或時間戳方法,因為我希望在正常情況下緩存所有圖像。

為什么你不能使用時間戳(或 etag,這相當於同一件事)? 請記住,您應該使用圖像文件本身的時間戳,而不僅僅是Time.Now
我討厭成為壞消息的承載者,但你別無選擇。

如果圖像沒有改變,時間戳也不會改變,所以一切都將“在正常情況下”緩存。 如果圖像確實發生了變化,他們將獲得一個新的時間戳(出於緩存原因,他們需要這樣做),但是該時間戳將永遠有效,直到有人再次替換該圖像。

由於這里的大多數(如果不是全部)答案和評論都是問題部分的副本,或者足夠接近,我將投入 2 美分。

我只想指出,即使有一種方法,也很難實施。 它的邏輯使我們陷入困境。 從邏輯立場來看,告訴瀏覽器為自某個日期以來列表中每個更改的圖像替換它的緩存圖像是理想的但是......你什么時候拿下列表,你怎么知道每個人是否都有最新版本的人會訪問再次?

所以我的第一個“建議”,正如 OP 所要求的,是這個列表理論。

我怎么看這樣做是:

A.) 有一個可以存儲我們動態和手動更改的圖像 URL 的列表。

B.) 設置一個截止日期,在此日期將重置捕獲並且無論如何都會截斷列表。

C.0) 通過 i 框架檢查站點入口與瀏覽器上的列表,該框架可以在后台運行,並設置較短的緩存標頭,以針對列表中的最遠日期或類似性質的日期重新緩存它們。

C.1) 使用 Iframe 或 ajax/xhr 請求我認為您可以遍歷列表中的每個圖像,刷新頁面以顯示不同的圖像,並根據自己的修改日期檢查緩存。 因此,在此圖像的 onload 上,使用服務器端來解密它是否在加載時不是最后一個圖像,請轉到下一個圖像。

C.1a) 這意味着我們的列表可能需要每個圖像的更多信息,我認為明顯的一個是可能需要一些服務器端腳本來調整每個圖像所需的標題,以盡量減少重新緩存更改站點的腳步圖片。

我的第二個“建議”是通知用戶更改並指導他們清除緩存。 (小心,盡可能只刪除圖像和文件,或警告他們由於該過程而刪除數據)

PS 這只是一個受過教育的想法。 一個快速的理論。 如果/當我成功時,我將發布決賽。 可能不在這里,因為它需要服務器端腳本。 這至少是 OP 的問題中沒有提到的一個建議,他說他已經嘗試過了。

經過多次測試,我通過以下方式找到了解決方案。

1-我創建一個臨時文件夾來復制名稱為添加時間 () .. 的圖像(如果該文件夾存在,我將刪除內容)

2- 從該臨時本地文件夾加載圖像

通過這種方式,我始終確保瀏覽器從不緩存圖像並且 100% 正確工作。

if (!is_dir(getcwd(). 'articulostemp')){
    $oldmask = umask(0);mkdir(getcwd(). 'articulostemp', 0775);umask($oldmask);
}else{
    rrmfiles(getcwd(). 'articulostemp');
}   
foreach ($images as $image) { 
    $tmpname = time().'-'.$image;
    $srcimage = getcwd().'articulos/'.$image;
    $tmpimage = getcwd().'articulostemp/'.$tmpname;
    copy($srcimage,$tmpimage);
    $urlimage='articulostemp/'.$tmpname;
    echo '  <img loading="lazy" src="'.$urlimage.'"/>   ';                  
}

嘗試以下解決方案,

myImg.src = " http://localhost/image.jpg ?" + 新日期().getTime();

以上解決方案對我有用:)

試試這個代碼片段:

var url = imgUrl? + Math.random();

這將確保每個請求都是唯一的,因此您將始終獲得最新的圖像。

我通常和@Greg 告訴我們的一樣,我有一個功能:

function addMagicRefresh(url)
{
    var symbol = url.indexOf('?') == -1 ? '?' : '&';
    var magic = Math.random()*999999;
    return url + symbol + 'magic=' + magic;
}

這將起作用,因為您的服務器接受它並且您不會以任何其他方式使用“magic”參數。

我希望它有幫助。

我嘗試了一些非常簡單的事情:

轉到網站的 FTP 文件夾並將 IMG 文件夾重命名為 IMG2。 刷新您的網站,您將看到圖像將丟失。 然后將文件夾 IMG2 重命名回 IMG 就完成了,至少它在 Safari 中對我有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM