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

Фон

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

Эта проблема

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

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

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

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

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

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

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

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

Заметки

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

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

Вопрос

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

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

20 ответов

Решение

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

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

где "1222259157.415" - текущее время на сервере. (Примечание: я использовал 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 так популярен;)

Используйте 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"

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

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

вначале.

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

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

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

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

Однако моя проблема была немного иной: я загружал на лету сгенерированное изображение php-диаграммы и управлял страницей с помощью параметров $_GET. Я хотел, чтобы изображение считывалось из кеша, когда параметр GET URL-адреса остается прежним, и не кэшировалось при изменении параметров 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 () возвращает время изменения файла.

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

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

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

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

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

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

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

Вы должны использовать уникальные имена файлов. Нравится

<img src="cars.png?1287361287" alt="">

Но этот метод означает высокую загрузку сервера и потерю полосы пропускания. Вместо этого вы должны использовать номер версии или дату. Пример:

<img src="cars.png?2020-02-18" alt="">

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

<img src="cars.png?<?php echo time();?>" alt="">

Однако это все равно неэффективно. Причина: кеш браузера... Последний, но наиболее эффективный метод - это Native JAVASCRIPT. Этот простой код находит все изображения с классом "NO-CACHE" и делает изображения почти уникальными. Поместите это между тегами скрипта.

var items = document.querySelectorAll("img.NO-CACHE");
for (var i = items.length; i--;) {
    var img = items[i];
    img.src = img.src + '?' + Date.now();
}

ПРИМЕНЕНИЕ

<img class="NO-CACHE" src="https://upload.wikimedia.org/wikipedia/commons/6/6a/JavaScript-logo.png" alt="">

РЕЗУЛЬТАТ (ы) как это

https://example.com/image.png?1582018163634

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

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

Я разместил код для этого в своем ответе здесь.

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

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

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

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

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

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

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

В этом случае, добавление некоторого параметра random/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>

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

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

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

Я обнаружил, что Chrome специально пытается разобраться с решением аргументов URL для изображений. Этот метод избежать кеша работает только в некоторых случаях. Самое надежное решение, которое я нашел, - это добавить как аргумент URL (например, отметку времени или версию файла), так и изменить использование заглавных букв в расширении файла изображения в URL-адресе.

      <img src="picture.jpg">

становится

      <img src="picture.JPG?t=current_time">

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

      caches.open('YOUR_CACHE_NAME').then(cache => {
  const url = 'URL_OF_IMAGE_TO_UPDATE'
  fetch(url).then(res => {
    cache.put(url, res.clone())
  })
})

cache.putобновляет кеш новым ответом.

подробнее: https://developer.mozilla.org/en-US/docs/Web/API/Cache/put

Я сделал PHP-скрипт, который автоматически добавляет временные метки для всех изображений на HTML-странице. Вам просто нужно включить этот скрипт на свои страницы. Наслаждайтесь!

http://alv90.altervista.org/how-to-force-the-browser-not-to-cache-images/

Лучшее решение - предоставить текущее время в конце исходного href, например <img src="www.abc.com/123.png?t=current_time">

это уберет вероятность ссылки на уже кешированное изображение. Чтобы узнать последнее время, можно использовать performance.now() функция в jQuery или javascript.

Другие вопросы по тегам