Вопрос

Предыстория

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

В Чем Проблема

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

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

Проблема в том, что показанное изображение не делает освежитесь.Старое изображение по-прежнему отображается, даже если в базе данных есть нужное изображение.Я сузил поиск до того факта, что ИЗОБРАЖЕНИЕ КЭШИРУЕТСЯ в веб-браузере.Если администратор нажимает кнопку ПЕРЕЗАГРУЗКИ в Firefox / Explorer / Safari, все обновляется нормально, и новое изображение просто появляется.

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

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

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

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

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

Примечания

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

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

Вопрос

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

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

Это было полезно?

Решение

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

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

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

Другие советы

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

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

Что говорит HTTP RFC:

Cache-Control: no-cache

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

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

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

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

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

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

где "20130910043254" - это время модификации файла.

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

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

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

HTML:

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

Сценарий:

// 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 изображения должно быть достаточно, но поскольку мы хотим быть пуленепробиваемыми..

Я НАЧИНАЮЩИЙ программист, но вот что я придумал, чтобы запретить браузеру кэшировать и сохранять мои просмотры с веб-камеры:

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

Не уверен, что работает в каком браузере, но для некоторых это работает:Т. Е.:Работает при обновлении веб-страницы и повторном посещении веб-сайта (без обновления).ХРОМ:Работает только при обновлении веб-страницы (даже после повторного посещения).SAFARI и iPad:Не работает, я должен очистить Историю и веб-данные.

Есть идеи по SAFARI / iPad?

использование Class="БЕЗКЭША"

пример 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="изображения/img1.jpg?a=0.08749723793963926"

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

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

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

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

<img src="image.png?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() возвращает время изменения файла.

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

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

Я опубликовал некоторый код для этого в своем ответе здесь.

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

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

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

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

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

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

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

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

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

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

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

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

Для этого вам следует отслеживать ресурсы, которые, возможно, потребуется синхронизировать, и либо использовать 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>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top