Wyłącz pamięć podręczną dla niektórych obrazów

113

Generuję obrazy za pomocą biblioteki PHP.

Czasami przeglądarka nie ładuje nowo wygenerowanego pliku.

Jak mogę wyłączyć pamięć podręczną tylko dla obrazów tworzonych dynamicznie przeze mnie?

Uwaga: z czasem muszę używać tej samej nazwy dla tworzonych obrazów.

zasiłek doug
źródło

Odpowiedzi:

233

Typowym i prostym rozwiązaniem tego problemu, które wygląda jak włamanie, ale jest dość przenośne, jest dodanie losowo wygenerowanego ciągu zapytania do każdego żądania dotyczącego obrazu dynamicznego.

Na przykład -

<img src="image.png" />

Stanie się

<img src="image.png?dummy=8484744" />

Lub

<img src="image.png?dummy=371662" />

Z punktu widzenia serwera internetowego dostęp do tego samego pliku jest możliwy, ale z punktu widzenia przeglądarki nie można wykonać buforowania.

Generowanie liczb losowych może odbywać się na serwerze podczas udostępniania strony (po prostu upewnij się, że sama strona nie jest buforowana ...) lub na kliencie (przy użyciu JavaScript).

Będziesz musiał sprawdzić, czy Twój serwer WWW może sobie z tym poradzić.

Sześciokąt
źródło
87
Zamiast liczb losowych użyj sygnatury czasowej zmiany danych lub numeru wersji odzwierciedlonych danych.
lhunath
19
Uwaga: w rzeczywistości nie uniemożliwiasz przeglądarce buforowania obrazu, zapobiegasz tylko przeglądaniu obrazu w pamięci podręcznej. Stosowanie odpowiednich nagłówków do obrazu to najlepszy sposób na imho (zobacz rozwiązanie lhunath poniżej). Ponieważ w ten sposób niepotrzebnie wypełniasz pamięć podręczną obrazami, których nie chcesz buforować, kosztem zmniejszenia miejsca w pamięci podręcznej na rzeczy, które faktycznie chcesz buforować.
Jos
Uważam, że ten artykuł wyjaśnia przyczynę takiego zachowania.
Metalcoder
1
to tak naprawdę nie działa, obraz musi zostać spłukany w inny sposób (zwykle podczas przycinania obrazu obraz pozostaje taki sam)
Ben
44

Strategie buforowania przeglądarki mogą być kontrolowane przez nagłówki HTTP. Pamiętaj, że tak naprawdę to tylko podpowiedź. Ponieważ przeglądarki są bardzo niespójne w tym (i każdym innym) polu, będziesz potrzebować kilku nagłówków, aby uzyskać pożądany efekt w różnych przeglądarkach.

header ("Pragma-directive: no-cache");
header ("Cache-directive: no-cache");
header ("Cache-control: no-cache");
header ("Pragma: no-cache");
header ("Expires: 0");
lhunath
źródło
1
to będzie dotyczyło całej strony .... Nie mogę wyłączyć pamięci podręcznej tylko dla jednego obrazu (określonego obrazu z tej strony)?
zasiłek doug
5
@Thorpe: Dotyczy odpowiedzi HTTP. To, co zawiera odpowiedź, nie ma znaczenia. Niezależnie od tego, czy są to dane obrazu, dane HTML czy cokolwiek innego. Jeśli to nie zadziałało, prawdopodobnie nie zrobiłeś tego dobrze. Sprawdź nagłówki HTTP w swojej odpowiedzi, aby zobaczyć, czy zostały poprawnie przypisane.
lhunath
Chciałbym, żeby to zadziałało ... Chrome nie ma żadnych problemów, ale Firefox 14 i IE 8 odmawiają odświeżania obrazów nawet przy wysyłaniu powyższych nagłówków. Byłoby to o wiele czystsze rozwiązanie niż dodanie niektórych dowolnych parametrów do ciągu zapytania. westchnienie
Paweł Krakowiak
2
@PawelKrakowiak Pamiętaj, że dodawanie nagłówków nie zadziała w przypadku obrazów, które są już w pamięci podręcznej , ponieważ przeglądarka nawet nie pyta o nie serwera i dlatego nigdy nie zobaczy nagłówków. Będą działać dla wszystkich żądań obrazów zgłoszonych po ich dodaniu.
lhunath
2
To rozwiązanie jest przeznaczone dla programistów, a nie projektantów stron internetowych. Pomyślałem, że zwróciłbym na to uwagę, ponieważ nie można po prostu otworzyć, wyobrazić sobie i dodać nagłówków do obrazu, chyba że oni sami generują obraz w języku programowania, co wydaje się być mylące dla komentatorów.
Bruce
13

Jeśli chcesz to zrobić dynamicznie w przeglądarce za pomocą javascript, oto przykład ...

<img id=graph alt="" 
  src="http://www.kitco.com/images/live/gold.gif" 
  />

<script language="javascript" type="text/javascript">
    var d = new Date(); 
    document.getElementById("graph").src = 
      "http://www.kitco.com/images/live/gold.gif?ver=" + 
       d.getTime();
</script>
Anton Swanevelder
źródło
12

Rozwiązanie 1 nie jest świetne. To działa, ale dodanie hackerskich, losowych lub oznaczonych czasem ciągów zapytań na końcu plików graficznych spowoduje, że przeglądarka ponownie pobierze i buforuje każdą wersję każdego obrazu, za każdym razem, gdy strona jest ładowana, niezależnie od pogody, czy obraz się zmienił na serwerze.

Rozwiązanie 2 jest bezużyteczne. Dodawanie nocachenagłówków do pliku obrazu jest nie tylko bardzo trudne do zaimplementowania, ale jest całkowicie niepraktyczne, ponieważ wymaga przewidywania, kiedy będzie to potrzebne z wyprzedzeniem , przy pierwszym ładowaniu dowolnego obrazu, który według Ciebie może się zmienić w pewnym momencie w przyszłości .

Wpisz Etags ...

Absolutnie najlepszy sposób znalazłem rozwiązania tego problemu jest użycie Etags wewnątrz .htaccess pliku w katalogu obrazów. Poniższe polecenie nakazuje Apache wysłanie unikalnego skrótu do przeglądarki w nagłówkach pliku obrazu. Ten hash zmienia się tylko wtedy, gdy plik obrazu jest modyfikowany i ta zmiana powoduje ponowne załadowanie obrazu przez przeglądarkę przy następnym żądaniu.

<FilesMatch "\.(jpg|jpeg)$">
FileETag MTime Size
</FilesMatch>
cronoklee
źródło
11

Sprawdziłem wszystkie odpowiedzi i wydawało się, że najlepsza (a nie jest):

<img src="image.png?cache=none">

najpierw.

Jeśli jednak dodasz parametr cache = none (które jest statycznym słowem „none”), to nic nie zmienia, przeglądarka nadal ładuje się z pamięci podręcznej.

Rozwiązaniem tego problemu było:

<img src="image.png?nocache=<?php echo time(); ?>">

gdzie zasadniczo dodajesz uniksowy znacznik czasu, aby parametr był dynamiczny i nie miał pamięci podręcznej, zadziałało.

Jednak mój problem był trochę inny: ładowałem w locie wygenerowany obraz wykresu php i kontrolowałem stronę za pomocą parametrów $ _GET. Chciałem, aby obraz był odczytywany z pamięci podręcznej, gdy parametr GET adresu URL pozostaje taki sam, i nie buforował, gdy zmieniają się parametry GET.

Aby rozwiązać ten problem, musiałem haszować $ _GET, ale ponieważ jest to tablica, oto rozwiązanie:

$chart_hash = md5(implode('-', $_GET));
echo "<img src='/images/mychart.png?hash=$chart_hash'>";

Edycja :

Chociaż powyższe rozwiązanie działa dobrze, czasami chcesz udostępniać wersję z pamięci podręcznej do momentu zmiany pliku. (przy powyższym rozwiązaniu całkowicie wyłącza pamięć podręczną dla tego obrazu) Tak więc, aby wyświetlać buforowany obraz z przeglądarki, DO DOPÓKI nastąpi zmiana w użyciu pliku obrazu:

echo "<img src='/images/mychart.png?hash=" . filemtime('mychart.png') . "'>";

filemtime () pobiera czas modyfikacji pliku.

Tarik
źródło
4

Wiem, że ten temat jest stary, ale w Google zajmuje bardzo dobre miejsce. Dowiedziałem się, że umieszczenie tego w nagłówku działa dobrze;

<meta Http-Equiv="Cache-Control" Content="no-cache">
<meta Http-Equiv="Pragma" Content="no-cache">
<meta Http-Equiv="Expires" Content="0">
<meta Http-Equiv="Pragma-directive: no-cache">
<meta Http-Equiv="Cache-directive: no-cache">
Dimitri Visser
źródło
Nowoczesne przeglądarki niestety ignorują te dyrektywy, dlatego to rozwiązanie może działać tylko na niektórych przeglądarkach, a także wyłączy pamięć podręczną dla wszystkiego, nie tylko dla określonych obrazów
ZioCain
4

Szukałem tylko rozwiązania tego problemu, a powyższe odpowiedzi nie zadziałały w moim przypadku (i nie mam wystarczającej reputacji, aby je komentować). Okazuje się, że przynajmniej dla mojego przypadku użycia i przeglądarki, której używałem (Chrome na OSX), jedyną rzeczą, która wydawała się zapobiegać buforowaniu, było:

Cache-Control = 'no-store'

Aby uzyskać kompletność, używam teraz wszystkich 3 opcji „no-cache, no-store, must-revalidate”

Więc w moim przypadku (obsługując dynamicznie generowane obrazy z Flaska w Pythonie), musiałem wykonać następujące czynności, aby mieć nadzieję, że pracowałem w jak największej liczbie przeglądarek ...

def make_uncached_response(inFile):
    response = make_response(inFile)
    response.headers['Pragma-Directive'] = 'no-cache'
    response.headers['Cache-Directive'] = 'no-cache'
    response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
    response.headers['Pragma'] = 'no-cache'
    response.headers['Expires'] = '0'
    return response
znak
źródło
Wystarczyło
odrzucić
Działa nie tylko w przeglądarce Chrome, ale także w przeglądarce Firefox. Wygląda na to, że jest teraz standardem: developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control (zobacz sekcję „ Zapobieganie buforowaniu ”).
Gino Mempin
3

Rozwiązaniem jest zmiana źródła obrazu. Rzeczywiście możesz to zrobić, dodając do obrazu znacznik czasu lub losową liczbę.

Lepiej byłoby dodać sumę kontrolną np. Danych, które reprezentuje obraz. Umożliwia to buforowanie, gdy jest to możliwe.

Stefan van Gastel
źródło
1

Dodajmy jeszcze jedno rozwiązanie do paczki.

Doskonałym rozwiązaniem jest dodanie na końcu unikalnego sznurka.

example.jpg?646413154

Poniższe rozwiązanie rozszerza tę metodę i zapewnia zarówno możliwość buforowania, jak i pobieranie nowej wersji po zaktualizowaniu obrazu.

Gdy obraz zostanie zaktualizowany, czas pliku zostanie zmieniony.

<?php
$filename = "path/to/images/example.jpg";
$filemtime = filemtime($filename);
?>

Teraz wytwórz obraz:

<img src="images/example.jpg?<?php echo $filemtime; ?>" >
Daniel
źródło
1
Właśnie tego użyłem ze względu na ważność buforowania.
gen
1

Miałem ten problem i pokonywałem się w ten sposób

var newtags='<div class="addedimage"><h5>preview image</h5><img src="'+one+'?nocache='+Math.floor(Math.random() * 1000)+'"></div>';
Jordan Georgiadis
źródło
0

Użyłem tego do rozwiązania podobnego problemu ... wyświetlania licznika obrazów (od zewnętrznego dostawcy). Nie zawsze odświeżał się poprawnie. A po dodaniu losowego parametru wszystko działa dobrze :)

Dodałem ciąg daty, aby zapewnić odświeżanie przynajmniej co minutę.

przykładowy kod (PHP):

$output .= "<img src=\"http://xy.somecounter.com/?id=1234567890&".date(ymdHi)."\" alt=\"somecounter.com\" style=\"border:none;\">";

Powoduje to srclink taki jak:

http://xy.somecounter.com/?id=1234567890&1207241014
Pinoccio
źródło
0

Jeśli masz zakodowany adres URL obrazu, na przykład: http://example.com/image.jpg , możesz użyć php, aby dodać nagłówki do obrazu.

Najpierw musisz sprawić, by apache przetwarzał twój plik jpg jako php. Zobacz tutaj: Czy można uruchomić PHP z rozszerzeniem file.php.jpg?

Załaduj obraz (imagecreatefromjpeg) z pliku, a następnie dodaj nagłówki z poprzednich odpowiedzi. Użyj nagłówka funkcji php, aby dodać nagłówki.

Następnie wyślij obraz za pomocą funkcji imagejpeg.

Proszę zauważyć, że zezwolenie php na przetwarzanie obrazów jpg jest bardzo niebezpieczne. Pamiętaj też, że nie testowałem tego rozwiązania, więc to od Ciebie zależy, czy zadziała.

Sam Sam
źródło
-1

Proste, wyślij jedną lokalizację nagłówka.

Moja witryna zawiera jeden obrazek, a po wgraniu obrazka nie ma zmian, wtedy dodaję ten kod:

<?php header("Location: pagelocalimage.php"); ?>

Pracuje dla mnie.

Programador
źródło