Как заставить веб-браузер не кэшировать изображения

Фон

Я пишу и использую очень простой инструмент управления контентом на основе CGI (Perl) для двух сайтов pro-bono. Он предоставляет администратору веб-сайта HTML-формы для событий, где они заполняют поля (дата, место, название, описание, ссылки и т.д.) И сохраняют его. В этой форме я разрешаю администратору загружать изображение, связанное с событием. На странице HTML, отображающей форму, я также показываю предварительный просмотр загруженного изображения (тег HTML img).

Проблема

Проблема возникает, когда администратор хочет изменить изображение. Ему просто нужно нажать кнопку "просмотреть", выбрать новую картинку и нажать "ОК". И это прекрасно работает.

После загрузки изображения мой внутренний CGI обрабатывает загрузку и перезагружает форму.

Проблема заключается в том, что изображение, показанное , не обновляется. Старое изображение все еще отображается, хотя база данных содержит правильное изображение. Я сузил его до того, что IMAGE IS CACHED в веб-браузере. Если администратор нажимает кнопку RELOAD в Firefox/Explorer/Safari, все становится хорошо обновленным и появляется новое изображение.

Мое решение - не работает

Я пытаюсь управлять кешем, написав инструкцию HTTP Expires с датой, очень далекой в ​​прошлом.

Expires: Mon, 15 Sep 2003 1:00:00 GMT

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

Но это тоже не работает.

Примечания

При загрузке изображения его имя не сохраняется в базе данных. Он переименовывается как Image.jpg (просто для использования при его использовании). При замене существующего изображения на новое имя также не изменяется. Просто изменяется содержимое файла изображения.

Веб-сервер предоставляется службой хостинга /ISP. Он использует Apache.

Вопрос

Есть ли способ заставить веб-браузер НЕ кэшировать вещи с этой страницы, даже изображения?

Я жонглирую с возможностью фактически "сохранить имя файла" в базе данных. Таким образом, если изображение будет изменено, src тега IMG также изменится. Однако для этого требуется много изменений на всем сайте, и я не хочу этого делать, если у меня есть лучшее решение. Кроме того, это все равно не будет работать, если новое загруженное изображение имеет одно и то же имя (скажем, изображение немного портировано и повторно загружено).

Ответ 1

Армин Роначер имеет правильную идею. Проблема в том, что случайные строки могут сталкиваться. Я хотел бы использовать:

<img src="picture.jpg?1222259157.415" alt="">

Где "1222259157.415" - текущее время на сервере.
Генерируйте время с помощью Javascript с помощью performance.now() или с помощью Python с помощью time.time()

Ответ 2

Простое исправление: присоедините произвольную строку запроса к изображению:

<img src="foo.cgi?random=323527528432525.24234" alt="">

Что сообщает HTTP RFC:

Cache-Control: no-cache

Но это не так хорошо работает:)

Ответ 3

Я использую функцию изменения времени файла PHP, например:

echo <img  src='Images/image.png?" . filemtime('Images/image.png') . "'  />";

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

Ответ 4

Я бы использовал:

<img src="picture.jpg?20130910043254">

где "20130910043254" - время изменения файла.

При загрузке изображения его имя не сохраняется в базе данных. Он переименован в Image.jpg(просто для использования при его использовании). При замене существующего изображения на новое имя также не изменяется. Просто изменяется содержимое файла изображения.

Я думаю, что есть два типа простых решений: 1) те, которые приходят на ум сначала (прямые решения, потому что их легко придумать), 2) те, с которыми вы закончили, подумав над чем-то (потому что они просты в использовании). По-видимому, вы не всегда будете в выигрыше, если захотите подумать. Но, по-моему, другие варианты довольно недооцениваются. Подумайте, почему php так популярен;)

Ответ 5

Вы можете написать прокси script для обслуживания изображений - это немного больше работает. Что-то нравится:

HTML:

<img src="image.php?img=imageFile.jpg&some-random-number-262376" />

Script:

// PHP
if( isset( $_GET['img'] ) && is_file( IMG_PATH . $_GET['img'] ) ) {

  // read contents
  $f = open( IMG_PATH . $_GET['img'] );
  $img = $f.read();
  $f.close();

  // no-cache headers - complete set
  // these copied from [php.net/header][1], tested myself - works
  header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Some time in the past
  header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 
  header("Cache-Control: no-store, no-cache, must-revalidate"); 
  header("Cache-Control: post-check=0, pre-check=0", false); 
  header("Pragma: no-cache"); 

  // image related headers
  header('Accept-Ranges: bytes');
  header('Content-Length: '.strlen( $img )); // How many bytes we're going to send
  header('Content-Type: image/jpeg'); // or image/png etc

  // actual image
  echo $img;
  exit();
}

На самом деле, либо заголовки без кеша, либо случайное число на изображении src должны быть достаточными, но поскольку мы хотим быть доказанными пулями.

Ответ 6

Я НОВЫЙ Coder, но вот что я придумал, чтобы остановить браузер от кеширования и удерживания на моих представлениях в веб-камерах:

<meta Http-Equiv="Cache" content="no-cache">
<meta Http-Equiv="Pragma-Control" content="no-cache">
<meta Http-Equiv="Cache-directive" Content="no-cache">
<meta Http-Equiv="Pragma-directive" Content="no-cache">
<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">

Не уверен, что работает над тем, что браузер, но он работает для некоторых: IE: Работает, когда веб-страница обновляется и когда веб-сайт пересматривается (без обновления). CHROME: Работает только при обновлении веб-страницы (даже после повторного просмотра). SAFARI и iPad: не работает, мне нужно очистить историю и веб-данные.

Любые идеи на SAFARI/iPad?

Ответ 7

используйте class= "NO-CACHE"

Пример HTML:

<div>
    <img class="NO-CACHE" src="images/img1.jpg" />
    <img class="NO-CACHE" src="images/imgLogo.jpg" />
</div>

JQuery:

    $(document).ready(function ()
    {           
        $('.NO-CACHE').attr('src',function () { return $(this).attr('src') + "?a=" + Math.random() });
    });

JavaScript:

var nods = document.getElementsByClassName('NO-CACHE');
for (var i = 0; i < nods.length; i++)
{
    nods[i].attributes['src'].value += "?a=" + Math.random();
}

Результат: src= "images/img1.jpg" => src= "images/img1.jpg? A = 0.08749723793963926"

Ответ 8

При загрузке изображения его имя не сохраняется в базе данных. Он переименовывается как Image.jpg(просто для использования при его использовании).

Измените это, и вы исправили свою проблему. Я использую временные метки, как и предлагаемые выше решения: Image- <timestamp> .jpg

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

Ответ 9

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

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

.

Однако, если вы добавите параметр cache = 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'>";

Edit

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

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

filemtime() получает время изменения файла.

Ответ 10

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

У меня была очень похожая ситуация с загрузкой изображений продуктов в бэкэнде администратора для хранилища, подобного сайту, и в моем случае я решил, что лучшим вариантом было использование javascript для принудительного обновления изображения без использования какого-либо URL-модификации техники, которые уже упоминались здесь. Вместо этого я помещал URL-адрес изображения в скрытый IFRAME, называемый location.reload(true) в окне IFRAME, а затем заменял свое изображение на странице. Это заставляет обновлять изображение не только на странице, на которой я работаю, но и на любых последующих страницах, которые я посещаю, - ни клиент, ни сервер не должны помнить какие-либо URL-запросы или параметры идентификатора фрагмента.

Я отправил код, чтобы сделать это в своем ответе здесь.

Ответ 11

Добавьте метку времени <img src="picture.jpg?t=<?php echo time();?>">

всегда будет давать вашему файлу случайное число в конце и останавливать его кеширование

Ответ 12

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

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

Ответ 13

Я предполагаю, что исходный вопрос касается изображений, сохраненных с некоторой текстовой информацией. Таким образом, если у вас есть доступ к текстовому контексту при генерации src=... url, рассмотрите использование/использование CRC32 байтов изображения вместо бессмысленной случайной или временной отметки. Затем, если страница с большим количеством изображений отображается, обновляются только обновленные изображения. В конце концов, если сохранение CRC невозможно, оно может быть вычислено и добавлено к URL-адресу во время выполнения.

Ответ 14

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

Коренная проблема здесь - как заставить браузер обновлять изображение, когда он был обновлен на стороне сервера.

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

В моем случае это служба отдыха, которая возвращает изображение и прикрепляет ETag в ответ. Служба сохраняет хэш всех файлов, если файл изменен, хеш обновляется. Он отлично работает во всех современных браузерах. Да, для его реализации требуется время, но оно того стоит.

Единственное исключение - это значки. По некоторым причинам это не работает. Я не мог заставить браузер обновлять кеш с сервера. ETags, Cache Control, Expires, заголовки Pragma, ничего не помогли.

В этом случае добавление некоторого параметра random/version в url, кажется, является единственным решением.

Ответ 15

В идеале, вы должны добавить кнопку/связывание клавиш/меню на каждую веб-страницу с возможностью синхронизации содержимого.

Для этого вы должны отслеживать ресурсы, которые могут потребоваться для синхронизации, и либо использовать xhr для проверки изображений с помощью динамической строки запроса, либо создавать изображение во время выполнения с помощью src, используя динамическую строку запроса. Затем используйте механизм широковещания, чтобы уведомить все компоненты веб-страниц, которые используют ресурс, для обновления, чтобы использовать ресурс с динамической строкой запроса, добавленной к его URL-адресу.

Наивный пример выглядит так:

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

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

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="mobile-web-app-capable" content="yes" />        
    <title>Resource Synchronization Test</title>
    <script>
function sync() {
    var xhr = new XMLHttpRequest;
    xhr.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {            
            var images = document.getElementsByClassName("depends-on-resource");

            for (var i = 0; i < images.length; ++i) {
                var image = images[i];
                if (image.getAttribute('data-resource-name') == 'resource.bmp') {
                    image.src = 'resource.bmp?i=' + new Date().getTime();                
                }
            }
        }
    }
    xhr.open('GET', 'resource.bmp', true);
    xhr.send();
}
    </script>
  </head>
  <body>
    <img class="depends-on-resource" data-resource-name="resource.bmp" src="resource.bmp"></img>
    <button onclick="sync()">sync</button>
  </body>
</html>