Отключить кеш для некоторых изображений


113

Я генерирую изображения с помощью библиотеки PHP.

Иногда браузер не загружает новый сгенерированный файл.

Как отключить кеш только для изображений, созданных мной динамически?

Примечание: я должен использовать одно и то же имя для создаваемых изображений с течением времени.

Ответы:


233

Распространенное и простое решение этой проблемы, которое выглядит как взлом, но довольно переносимо, - это добавлять случайно сгенерированную строку запроса к каждому запросу динамического изображения.

Так, например -

<img src="image.png" />

Станет

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

Или

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

С точки зрения веб-сервера осуществляется доступ к тому же файлу, но с точки зрения браузера кеширование невозможно.

Генерация случайных чисел может происходить либо на сервере при обслуживании страницы (просто убедитесь, что сама страница не кэширована ...), либо на клиенте (с использованием JavaScript).

Вам нужно будет проверить, может ли ваш веб-сервер справиться с этой уловкой.


87
Вместо случайных чисел используйте метку времени изменения данных или номер версии отраженных данных.
lhunath


19
Обратите внимание: на самом деле вы не запрещаете браузеру кэшировать изображение, вы только запрещаете просмотр кэшированного изображения. Применение правильных заголовков к вашему изображению - лучший способ imho (см. Решение lhunath ниже). Так как таким образом вы также без необходимости заполняете кеш изображениями, которые не хотите кэшировать, за счет уменьшения места в кеше для вещей, которые вы действительно хотите кэшировать.
Jos

Я считаю, что эта статья объясняет причину такого поведения.
Metalcoder 03

1
на самом деле это не работает, изображение нужно очистить другим способом (обычно при кадрировании изображения изображение остается прежним)
Бен

44

Стратегиями кэширования браузера можно управлять с помощью заголовков HTTP. Помните, что на самом деле они всего лишь намек. Поскольку браузеры ужасно несовместимы в этом (и в любом другом) поле, вам понадобится несколько заголовков, чтобы добиться желаемого эффекта в ряде браузеров.

header ("Pragma-directive: no-cache");
header ("Cache-directive: no-cache");
header ("Cache-control: no-cache");
header ("Pragma: no-cache");
header ("Expires: 0");

1
это будет применяться ко всей странице .... Я не могу отключить кеш только для одного изображения (определенного изображения с этой страницы)?
dole doug

5
@Thorpe: применяется к HTTP-ответам. То, что содержится в ответе, не имеет значения. Будь то данные изображения, данные HTML или что-то еще. Если это не сработало, вероятно, вы сделали это неправильно. Проверьте заголовки HTTP в своем ответе, чтобы убедиться, что они правильно назначены.
lhunath

Хотелось бы, чтобы это сработало ... У Chrome нет никаких проблем, но Firefox 14 и IE 8 отказываются обновлять изображения даже при отправке вышеуказанных заголовков. Это было бы намного более чистым решением, чем добавление произвольных параметров в строку запроса. вздох
Павел Краковяк

2
@PawelKrakowiak Обратите внимание, что добавление заголовков не будет работать для изображений, которые уже кэшированы , поскольку браузер даже не спрашивает о них сервер и, следовательно, никогда не увидит заголовки. Они будут работать для любых запросов изображений, сделанных после их добавления.
lhunath

2
Это решение предназначено для программистов, а не для веб-дизайнеров. Я подумал, что хочу указать на это, потому что нельзя просто открывать, отображать и добавлять заголовки к изображению, если они сами не генерируют изображение на языке программирования, и это, похоже, сбивает с толку комментаторов.
Брюс

13

Если вам нужно сделать это динамически в браузере с помощью javascript, вот пример ...

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

12

Решение 1 не очень хорошее.Это действительно работает, но добавление хакерских случайных строк или строк запроса с меткой времени в конец ваших файлов изображений заставит браузер повторно загружать и кэшировать каждую версию каждого изображения каждый раз, когда страница загружается, независимо от погоды, изменилось изображение или нет. на сервере.

Решение 2 бесполезно. Добавление nocacheзаголовков в файл изображения не только очень сложно реализовать, но и совершенно непрактично, поскольку требует от вас заранее предугадывать, когда он понадобится , при первой загрузке любого изображения, которое, по вашему мнению, может измениться в какой-то момент в будущем. .

Введите Etags ...

Самый лучший способ решить эту проблему - использовать ETAGS внутри файла .htaccess в каталоге изображений. Следующее указывает Apache отправлять уникальный хэш в браузер в заголовках файлов изображений. Этот хэш изменяется только при изменении файла изображения, и это изменение заставляет браузер перезагружать изображение при следующем запросе.

<FilesMatch "\.(jpg|jpeg)$">
FileETag MTime Size
</FilesMatch>

11

Я проверил все ответы, и мне показалось, что лучший (а это не так):

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

вначале.

Однако, если вы добавите cache = none (статическое слово «none»), это ни на что не повлияет, браузер по-прежнему загружается из кеша.

Решение этой проблемы было:

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

где вы в основном добавляете временную метку unix, чтобы сделать параметр динамическим и без кеша, это сработало.

Однако моя проблема была немного другой: я загружал на лету сгенерированное изображение php-диаграммы и контролировал страницу с параметрами $ _GET. Я хотел, чтобы изображение читалось из кеша, когда параметр URL GET остается неизменным, и не кешировался при изменении параметров GET.

Чтобы решить эту проблему, мне нужно было хешировать $ _GET, но поскольку это массив, вот решение:

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

Редактировать :

Хотя приведенное выше решение работает нормально, иногда вам нужно обслуживать кешированную версию ДО тех пор, пока файл не будет изменен. (с указанным выше решением он полностью отключает кеш для этого изображения) Итак, для обслуживания кэшированного изображения из браузера ДО ТОГО, как изменится использование файла изображения:

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

filemtime () получает время модификации файла.


4

Я знаю, что эта тема старая, но она очень хорошо оценивается в Google. Я обнаружил, что размещение этого текста в заголовке работает хорошо;

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

К сожалению, современный браузер игнорирует эти директивы, поэтому это решение может работать только в некоторых браузерах, а также отключит кеш для всего, а не только для определенных изображений
ZioCain

4

Я просто искал решение этой проблемы, и приведенные выше ответы не сработали в моем случае (и у меня недостаточно репутации, чтобы комментировать их). Оказывается, что, по крайней мере, для моего варианта использования и браузера, который я использовал (Chrome на OSX), единственное, что, казалось, могло предотвратить кеширование, это:

Cache-Control = 'no-store'

Для полноты картины я сейчас использую все три из следующих: «без кеширования, без хранения, с обязательной повторной проверкой»

Итак, в моем случае (обслуживание динамически сгенерированных изображений из Flask в Python) мне пришлось сделать следующее, чтобы, надеюсь, работать в максимально возможном количестве браузеров ...

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

Просто
отказать

Это не только в Chrome, но и в Firefox. Сейчас это кажется стандартом: developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control (см. Раздел « Предотвращение кеширования »).
Gino Mempin

3

Решением является изменение источника изображения. Вы действительно можете сделать это, добавив к изображению метку времени или случайное число.

Лучше было бы добавить контрольную сумму, например, данных, которые представляет изображение. Это позволяет кэшировать, когда это возможно.


1

Добавим еще одно решение в кучу.

Добавление уникальной строки в конце - идеальное решение.

example.jpg?646413154

Следующее решение расширяет этот метод и обеспечивает как возможность кэширования, так и получение новой версии при обновлении изображения.

Когда изображение обновляется, время файла будет изменено.

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

Теперь выведите изображение:

<img src="images/example.jpg?<?php echo $filemtime; ?>" >

1
Это то, что я использовал из-за действительности кеширования.
ген

1

У меня была эта проблема, и я ее преодолеваю.

var newtags='<div class="addedimage"><h5>preview image</h5><img src="'+one+'?nocache='+Math.floor(Math.random() * 1000)+'"></div>';

0

Я использовал это для решения своей аналогичной проблемы ... отображения счетчика изображений (от внешнего поставщика). Не всегда корректно обновлялось. И после добавления случайного параметра все работает нормально :)

Я добавил строку даты, чтобы обновлять ее хотя бы каждую минуту.

пример кода (PHP):

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

Это приводит к srcссылке вроде:

http://xy.somecounter.com/?id=1234567890&1207241014

0

Если у вас есть жестко запрограммированный URL-адрес изображения, например: http://example.com/image.jpg, вы можете использовать php для добавления заголовков к вашему изображению.

Сначала вам нужно будет заставить apache обрабатывать ваш jpg как php. Смотрите здесь: Можно ли выполнить PHP с расширением file.php.jpg?

Загрузите изображение (imagecreatefromjpeg) из файла, затем добавьте заголовки из предыдущих ответов. Используйте заголовок функции php, чтобы добавить заголовки.

Затем выведите изображение с помощью функции imagejpeg.

Обратите внимание, что разрешать php обрабатывать изображения jpg очень небезопасно. Также имейте в виду, что я не тестировал это решение, поэтому вам решать, как заставить его работать.


-1

Просто отправьте одно место заголовка.

Мой сайт содержит одно изображение, и после загрузки изображения оно не меняется, затем я добавляю этот код:

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

Работает для меня.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.