Я пишу и использую очень простой инструмент управления контентом на основе 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 = "foo.cgi?random=323527528432525.24234" alt = "">
Что говорит HTTP RFC:
Cache-Control: no-cache
Но это не так хорошо :)
как дать Cache-Control: no-cache в обычном теге html <img>?
Нужно ли это приходить в заголовке ответа?
Поскольку между вами и клиентом могут возникать прозрачные прокси с плохим поведением, единственный способ полностью гарантировать, что изображения не будут кэшироваться, - это дать им уникальный uri, что-то вроде отметки времени как строки запроса или как части путь.
Если эта отметка времени соответствует времени последнего обновления изображения, вы можете кэшировать, когда вам нужно, и обслуживать новое изображение в нужное время.
Армин Ронахер имеет правильное представление. Проблема в том, что случайные строки могут конфликтовать. Я хотел бы использовать:
<img src = "picture.jpg?1222259157.415" alt = "">
Где «1222259157.415» - текущее время на сервере.
Генерация времени с помощью Javascript с performance.now() или Python с time.time()
Одним из важных дополнений является то, что вы никогда не сможете сила браузеру делать что-либо. Все, что вы можете сделать, это сделать дружеские предложения. Фактически следовать этим предложениям - дело браузера и пользователя. Браузер может игнорировать это, или пользователь может изменить настройки по умолчанию.
Джоэл, тебе лучше было бы добавить это в свой ответ.
Просто мысль, и слишком поздно приходить сюда на вечеринку - но, поскольку вы контролируете изменение изображения, возможно, было бы лучше переименовать изображение по мере его обновления, а не добавлять строку запроса. Итак: 1222259157.jpg например, вместо picture.jpg? 1222259157. Таким образом, он обновляется и повторно кэшируется при повторном посещении.
@epochwolf некоторые серверы не позволяют добавлять текст после "?". Он просто возвращает сообщение «страница не найдена». Есть ли обходные пути?
Спасибо, что сработало нормально. Сломал себе шею, пытаясь понять, почему JQUery Ajax $ .get (...) не отображал новый ресурс (или даже фактически не выполнял вызов) в IE (когда во всех других браузерах он работал). Добавил милли-время что-то вроде $ .get ('/ rawData? Action = getLeftThumbId & bigImageId =' + bigImageI d + "& forceRefresh =" + n ew Date (). GetTime ()
привет. Интересно, решит ли проблему «cache-control» мета-мета html?
Вместо того, чтобы добавлять время сервера, что полностью предотвратит кеширование, почему бы не добавить время последнего изменения файла после символа «?». Таким образом, изображение будет кэшироваться в обычном режиме до следующего изменения.
За последний комментарий Doin нужно проголосовать! Умное кеширование действительно важно, зачем кому-то скачивать один и тот же файл снова и снова?
Я согласен, комментарий @Doin должен быть одобрен. Нет необходимости заставлять браузер получать изображение, когда вам это действительно не нужно.
-1 Это отключит кеширование, что сделает этот подход крайне неэффективным только для отладки, но не для любого производственного окружения.
@ for3st, почему голосование против? Это именно то, о чем был задан вопрос: как заставить веб-браузер НЕ кэшировать изображения. Другой вопрос, хорошая ли это идея.
@ for3st вы не должны голосовать против только потому, что вам не нравится вопрос. Иногда НЕОБХОДИМО обходить кеш; Это часто верно, если вы ожидаете, что ресурс будет обновляться очень часто, и этот ресурс важен для презентации. Иногда вы не можете позволить клиенту получить устаревший ресурс. В идеале вы делаете это только по запросу пользователя (например, добавляете кнопку, позволяющую пользователю вручную выбирать принудительный обход кеша), но иногда это дороже, когда вам нужно отправить дополнительные запросы, чтобы проверить, не синхронизирован ли он или нет, и добавление такой кнопки нежелательно.
@Dmitry Вы правы, спрашивающий задал неправильный вопрос (скорее, «Как справиться с этим» вместо «Как создать конкретный хакерский метод»). ИМХО, ответ состоит в том, чтобы создать неизменяемые ресурсы (т.е. уникальный URL-адрес, который включает хэш данных и неограниченное время кеширования), это было бы лучше всего из обоих миров и является лучшей практикой кеширования http. Смотрите здесь: developers.google.com/web/fundamentals/performance/…. Однако я все еще считаю, что это взлом.
@ for3st я согласен, что это своего рода взлом, поскольку вы не должны предполагать, что браузер не будет кэшировать ваш ресурс, даже если строка запроса меняется; Предполагается, что браузер достаточно настраиваемый для кеширования в любом случае, и если ресурс предназначен для динамического использования, URL-адрес ресурса также должен быть динамическим. К сожалению, сделать это значительно сложнее, чем иметь динамические строки запроса, и почти во всех случаях можно с уверенностью предположить, что динамическая строка запроса будет рассматриваться как совершенно новый ресурс и обходиться кешированием, поскольку в противном случае многие ресурсы и формы php / serveride перестанут работать правильно.
@ for3st на самом деле, если задуматься, вы не можете назвать это взломом, поскольку строка запроса является частью URL-адреса, и ни один браузер не может кэшировать различные ресурсы строки запроса, поскольку формы должны правильно вести себя во всем, что можно считать браузером общего назначения. Это умно, но это не взлом. Это просто уродливо в том смысле, что если вы запрашиваете «a? B = c», дальнейшие запросы для «a» могут по-прежнему использовать устаревший ресурс (даже если обновленная версия также находится в кеше), и я воочию убедился в этом в chrome.
Этим методом я пользуюсь с 2012 года и он эффективен. другие заголовки не будут работать должным образом. Иногда даже файлы CSS / Javacscript попадают в кеш. тот же метод случайной строки работает для этой проблемы.
Вы можете написать прокси-скрипт для обслуживания изображений - хотя это немного больше работы. Что-то вроде этого:
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 изображения, но поскольку мы хотим быть пуленепробиваемыми ...
Ваше решение - хорошее, за исключением того, что Pragma не является заголовком ответа.
@Piskvor: w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.32, кажется, говорит иначе.
When uploading an image, its filename is not kept in the database. It is renamed as Image.jpg (to simply things out when using it).
Измените это, и вы устранили свою проблему. Я использую временные метки, как и в решениях, предложенных выше: Изображение- <отметка времени> .jpg
По-видимому, любые проблемы, которых вы избегаете, сохраняя одно и то же имя файла для изображения, можно преодолеть, но вы не говорите, что они собой представляют.
Я предполагаю, что исходный вопрос касается изображений, хранящихся с некоторой текстовой информацией. Итак, если у вас есть доступ к текстовому контексту при генерации src = ... url, рассмотрите возможность сохранения / использования CRC32 байтов изображения вместо бессмысленной случайной метки или отметки времени. Затем, если отображается страница с большим количеством изображений, перезагружаются только обновленные изображения. В конце концов, если сохранение CRC невозможно, его можно вычислить и добавить к URL-адресу во время выполнения.
Или используйте время последнего изменения изображения вместо CRC, даже лучше!
Я использую Функция времени изменения файла PHP, например:
echo <img src='Images/image.png?" . filemtime('Images/image.png') . "' />";
Если вы измените изображение, то будет использоваться новое изображение, а не кэшированное из-за другой измененной временной метки.
Отличный совет. У вас есть и кеширование, и изображение, повторно отправленное клиенту, если его время изменения изменяется (перезаписывается или изменяется).
смотрите здесь другой вариант stackoverflow.com/questions/56588850/…
Absolute это удалось. Отличный помощник по чаевым.
Идеальный ! Еще один совет: <img src = "images / image.png? <? Php echo filemtime ('images / image.jpg')?>">
Я хотел бы использовать:
<img src = "picture.jpg?20130910043254">
где «20130910043254» - время модификации файла.
When uploading an image, its filename is not kept in the database. It is renamed as Image.jpg (to simply things out when using it). When replacing the existing image with a new one, the name doesn't change either. Just the content of the image file changes.
Я думаю, что есть два типа простых решений: 1) те, которые приходят в голову первыми (простые решения, потому что их легко придумать), 2) те, которые вы получаете после обдумывания (потому что их легко найти) использовать). По-видимому, вы не всегда будете получать выгоду, если решите все обдумать. Но я считаю, что второй вариант сильно недооценен. Вдумайтесь, почему php так популярен;)
+1 Я думаю, что это намного лучшая идея, чем другие ответы, потому что, используя время последней модификации, ваш сервер не будет пытаться передавать одно и то же изображение несколько раз в один и тот же браузер, если в изображении ничего не изменилось. Есть небольшие накладные расходы на извлечение времени последней записи изображения каждый раз, когда есть запрос, но для большого изображения это лучше, чем возвращать изображение каждый раз, и когда изображение изменится, у пользователя будет новое. Спасибо за это приятное маленькое дополнение.
Ну, можно было бы сохранить время модификации вместе с путем к изображению в базе данных. Так что накладные расходы могут быть еще менее значительными. С другой стороны, если это изображения, которые являются частью исходного кода, о котором мы говорим, можно также кэшировать время их модификации. Путем создания сценария с указанием времени модификации изображений (например, images.php). Этот сценарий необходимо регенерировать при каждой фиксации и устраняет накладные расходы на определение времени модификации файлов.
@ x-yori, поэтому я предпочитаю хранить это обновленное поле в базе данных, а не запускать filemtime stackoverflow.com/questions/56588850/…
Ваша проблема в том, что, несмотря на заголовок Expires:, ваш браузер повторно использует сохраненную в памяти копию изображения до его обновления, а не даже проверяет свой кеш.
У меня была очень похожая ситуация с загрузкой изображений продуктов в бэкэнд администратора для сайта, похожего на магазин, и в моем случае я решил, что лучшим вариантом было бы использовать javascript для принудительного обновления изображения без использования каких-либо методов изменения URL-адресов других людей. уже упоминали здесь. Вместо этого я помещаю URL-адрес изображения в скрытый IFRAME, называемый location.reload(true) в окне IFRAME, а затем заменяю свое изображение на странице. Это приводит к обновлению изображения не только на странице, на которой я нахожусь, но и на всех последующих страницах, которые я посещаю, без необходимости запоминания ни клиентом, ни сервером каких-либо параметров строки запроса URL или идентификатора фрагмента.
Я разместил код для этого в своем ответе здесь.
Я проверил все ответы в Интернете, и, похоже, лучший из них: (на самом деле это не так)
<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'>";
Редактировать:
Хотя приведенное выше решение работает нормально, иногда вы хотите обслуживать кешированную версию ДО тех пор, пока файл не будет изменен. (с вышеуказанным решением он полностью отключает кеш для этого изображения) Итак, для обслуживания кэшированного изображения из браузера ДО тех пор, пока не произойдет изменение в использовании файла изображения:
echo "<img src='/images/mychart.png?hash = " . filemtime('mychart.png') . "'>";
filemtime() gets file modification time.
Решение filemtime лучше еще и потому, что md5 требует большой вычислительной мощности.
Потрачены дни, пытаясь заставить приложение на основе Chromium перестать кэшировать изображения. Отсутствие кэша с эхом времени решило проблему. Спасибо!
С моей точки зрения, отключать кеширование изображений - плохая идея. Совсем.
Основная проблема здесь - как заставить браузер обновлять изображение, когда оно было обновлено на стороне сервера.
Опять же, с моей личной точки зрения, лучшее решение - отключить прямой доступ к изображениям. Вместо этого обращайтесь к изображениям через серверный фильтр / сервлет / другие аналогичные инструменты / службы.
В моем случае это сервис отдыха, который возвращает изображение и в ответ прикрепляет ETag. Сервис хранит хеш всех файлов, при изменении файла хеш обновляется. Он отлично работает во всех современных браузерах. Да, на это нужно время, но оно того стоит.
Единственное исключение - это фавиконы. По каким-то причинам не работает. Я не мог заставить браузер обновлять кеш со стороны сервера. Заголовки ETags, Cache Control, Expires, Pragma ничего не помогли.
В этом случае, кажется, единственное решение - добавить какой-нибудь параметр random / version в url.
Я НОВЫЙ кодировщик, но вот что я придумал, чтобы браузер не кешировал и не сохранял изображения с моей веб-камеры:
<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: работает при обновлении веб-страницы и при повторном посещении веб-сайта (без обновления). ХРОМ: работает только при обновлении веб-страницы (даже после повторного посещения). САФАРИ и iPad: не работает, мне нужно очистить историю и веб-данные.
Есть идеи по SAFARI / iPad?
используйте 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 = "picture.jpg?t=<?php echo time();?>">
всегда будет давать вашему файлу случайный номер в конце и останавливать его кеширование
Стоит отметить, что реализация этого решения создает нагрузку на сервер для каждого запроса и не обязательно будет работать, поскольку браузер может кэшировать страницу php, которая содержит время, сгенерированное во время первоначального запроса, который кэшируется. Это было бы надежно только в том случае, если бы страница также имела динамическую строку запроса.
В идеале вы должны добавить кнопку / привязку клавиш / меню к каждой веб-странице с возможностью синхронизации содержимого.
Для этого вы должны отслеживать ресурсы, которые могут нуждаться в синхронизации, и либо использовать 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>
Я сделал PHP-скрипт, который автоматически добавляет временные метки для всех изображений на HTML-странице. Вам просто нужно включить этот скрипт на свои страницы. Наслаждаться!
http://alv90.altervista.org/how-to-force-the-browser-not-to-cache-images/
Вы должны использовать уникальные имена файлов. Нравится
<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
Я думаю, что этот вопрос можно было бы переработать, чтобы удалить весь «бесполезный контекст», который я вставил там некоторое время назад, когда писал его. Я думаю, что название правильное, и самый лучший ответ. Но изначально вопрос был написан так, чтобы дать много места для многих ответов, и нельзя было ожидать такого простого решения. Поэтому вопрос немного запутан для людей, приходящих туда, чтобы получить ответ.