Pregunta

Fondo

Estoy escribiendo y utilizando una herramienta de gestión de contenidos muy sencilla basada en CGI (Perl) para dos sitios web gratuitos.Proporciona al administrador del sitio web formularios HTML para eventos donde completa los campos (fecha, lugar, título, descripción, enlaces, etc.) y los guarda.En ese formulario permito al administrador cargar una imagen relacionada con el evento.En la página HTML que muestra el formulario, también muestro una vista previa de la imagen cargada (etiqueta HTML img).

El problema

El problema ocurre cuando el administrador quiere cambiar la imagen.Sólo tendría que presionar el botón "examinar", elegir una nueva imagen y presionar Aceptar.Y esto funciona bien.

Una vez cargada la imagen, mi CGI de back-end maneja la carga y recarga el formulario correctamente.

El problema es que la imagen mostrada no es refréscate.La imagen antigua todavía se muestra, aunque la base de datos contiene la imagen correcta.Lo he reducido al hecho de que la IMAGEN ESTÁ EN CACHÉ en el navegador web.Si el administrador presiona el botón RECARGAR en Firefox/Explorer/Safari, todo se actualiza correctamente y simplemente aparece la nueva imagen.

Mi solución: no funciona

Estoy intentando controlar el caché escribiendo una instrucción HTTP Expires con una fecha muy lejana en el pasado.

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

Recuerden que estoy del lado administrativo y realmente no me importa si las páginas tardan un poco más en cargar porque siempre están caducadas.

Pero esto tampoco funciona.

Notas

Al cargar una imagen, su nombre de archivo no se guarda en la base de datos.Se renombra como Imagen.jpg (para simplificar las cosas al usarlo).Al reemplazar la imagen existente por una nueva, el nombre tampoco cambia.Sólo cambia el contenido del archivo de imagen.

El servidor web lo proporciona el servicio de hosting/ISP.Utiliza Apache.

Pregunta

¿Hay alguna manera de obligar al navegador web a NO almacenar en caché elementos de esta página, ni siquiera imágenes?

Estoy haciendo malabarismos con la opción de "guardar el nombre del archivo" con la base de datos.De esta manera, si se cambia la imagen, el src de la etiqueta IMG también cambiará.Sin embargo, esto requiere muchos cambios en todo el sitio y prefiero no hacerlo si tengo una solución mejor.Además, esto aún no funcionará si la nueva imagen cargada tiene el mismo nombre (digamos que la imagen se retocó un poco y se volvió a cargar).

¿Fue útil?

Solución

Armin Ronacher tiene la idea correcta.El problema es que las cadenas aleatorias pueden colisionar.Yo usaría:

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

Donde "1222259157.415" es la hora actual en el servidor.
Generar tiempo por Javascript con performance.now() o por Python con time.time()

Otros consejos

Solución sencilla:Adjunte una cadena de consulta aleatoria a la imagen:

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

Lo que dice el RFC HTTP:

Cache-Control: no-cache

Pero eso no funciona tan bien :)

yo suelo Función de hora de modificación de archivos de PHP, Por ejemplo:

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

Si cambia la imagen, se utiliza la nueva imagen en lugar de la almacenada en caché, debido a que tiene una marca de tiempo modificada diferente.

Yo usaría:

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

donde "20130910043254" es la hora de modificación del archivo.

Al cargar una imagen, su nombre de archivo no se guarda en la base de datos.Se le cambia el nombre a Imagen.jpg (para simplificar las cosas al usarlo).Al reemplazar la imagen existente por una nueva, el nombre tampoco cambia.Sólo cambia el contenido del archivo de imagen.

Creo que hay dos tipos de soluciones simples:1) aquellas que te vienen a la mente primero (soluciones sencillas, porque son fáciles de encontrar), 2) aquellas con las que terminas después de pensarlo bien (porque son fáciles de usar).Aparentemente, no siempre obtendrás beneficios si decides pensar las cosas detenidamente.Pero creo que la segunda opción está bastante subestimada.Sólo piensa por qué php es muy popular;)

Puede escribir un script proxy para servir imágenes; aunque eso requiere un poco más de trabajo.Algo como esto:

HTML:

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

Guion:

// 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();
}

En realidad, los encabezados sin caché o un número aleatorio en el origen de la imagen deberían ser suficientes, pero como queremos ser a prueba de balas...

Soy un codificador NUEVO, pero esto es lo que se me ocurrió para evitar que el navegador almacene en caché y conserve las vistas de mi cámara web:

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

No estoy seguro de qué funciona en qué navegador, pero funciona para algunos:ES DECIR:Funciona cuando se actualiza la página web y cuando se vuelve a visitar el sitio web (sin actualización).CROMO:Funciona solo cuando se actualiza la página web (incluso después de una nueva visita).SAFARI y iPad:No funciona, tengo que borrar el historial y los datos web.

¿Alguna idea sobre SAFARI/iPad?

usar Clase="SIN CACHÉ"

html de muestra:

<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();
}

Resultado:src="imagenes/img1.jpg" => src="images/img1.jpg?a=0.08749723793963926"

Al cargar una imagen, su nombre de archivo no se guarda en la base de datos.Se le cambia el nombre a Imagen.jpg (para simplificar las cosas al usarlo).

Cambie esto y habrá solucionado su problema.Utilizo marcas de tiempo, como ocurre con las soluciones propuestas anteriormente: Imagen-<marca de tiempo>.jpg

Presumiblemente, cualquier problema que esté evitando al mantener el mismo nombre de archivo para la imagen se puede superar, pero no dice cuáles son.

Revisé todas las respuestas en la web y la mejor parecía ser:(en realidad no lo es)

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

en primer lugar.

Sin embargo, si agrega caché = ninguno parámetro (que es una palabra estática "ninguno"), no afecta a nada, el navegador aún se carga desde la memoria caché.

La solución a este problema fue:

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

donde básicamente agregas una marca de tiempo de Unix para que el parámetro sea dinámico y sin caché, funcionó.

Sin embargo, mi problema fue un poco diferente:Estaba cargando sobre la marcha una imagen de gráfico php generada y controlando la página con parámetros $_GET.Quería que la imagen se leyera desde la memoria caché cuando el parámetro GET de la URL permaneciera igual y no se almacenara en la memoria caché cuando los parámetros GET cambiaran.

Para resolver este problema, necesitaba hash $_GET pero como es una matriz, aquí está la solución:

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

Editar:

Aunque la solución anterior funciona bien, a veces desea servir la versión en caché HASTA que se cambie el archivo.(Con la solución anterior, deshabilita el caché para esa imagen por completo), por lo tanto, servir a la imagen en caché del navegador hasta que haya un cambio en el uso del archivo de la imagen:

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

filemtime() obtiene la hora de modificación del archivo.

Tu problema es que a pesar de Expires: encabezado, su navegador está reutilizando su copia en memoria de la imagen anterior a su actualización, en lugar de siquiera verificar su caché.

Tuve una situación muy similar al cargar imágenes de productos en el backend de administración de un sitio similar a una tienda y, en mi caso, decidí que la mejor opción era usar javascript para forzar la actualización de la imagen, sin usar ninguna de las técnicas de modificación de URL que otras personas utilizan. ya he mencionado aquí.En lugar de eso, puse la URL de la imagen en un IFRAME oculto, llamado location.reload(true) en la ventana del IFRAME y luego reemplacé mi imagen en la página.Esto fuerza una actualización de la imagen, no sólo en la página en la que estoy, sino también en cualquier página que visite posteriormente, sin que ni el cliente ni el servidor tengan que recordar ninguna cadena de consulta de URL o parámetros de identificador de fragmento.

Publiqué un código para hacer esto en mi respuesta. aquí.

Agregar una marca de tiempo <img src="picture.jpg?t=<?php echo time();?>">

siempre le dará a su archivo un número aleatorio al final y dejará de almacenarlo en caché

Con la posibilidad de que haya servidores proxy transparentes con mal comportamiento entre usted y el cliente, la única forma de garantizar totalmente que las imágenes no se almacenen en caché es darles un uri único, algo así como etiquetar una marca de tiempo como una cadena de consulta o como parte del camino.

Si esa marca de tiempo corresponde a la última hora de actualización de la imagen, entonces puede almacenar en caché cuando lo necesite y publicar la nueva imagen en el momento justo.

Supongo que la pregunta original se refiere a imágenes almacenadas con información de texto.Entonces, si tiene acceso a un contexto de texto al generar src=...URL, considere almacenar/usar CRC32 de bytes de imagen en lugar de una marca de tiempo o aleatoria sin sentido.Luego, si se muestra la página con muchas imágenes, solo se recargarán las imágenes actualizadas.Finalmente, si el almacenamiento de CRC es imposible, se puede calcular y agregar a la URL en tiempo de ejecución.

Desde mi punto de vista, desactivar el almacenamiento en caché de imágenes es una mala idea.En absoluto.

La raíz del problema aquí es cómo forzar al navegador a actualizar la imagen, cuando se ha actualizado en el lado del servidor.

Nuevamente, desde mi punto de vista personal, la mejor solución es desactivar el acceso directo a las imágenes.En su lugar, acceda a las imágenes a través de un filtro/servlet/otras herramientas/servicios similares del lado del servidor.

En mi caso es un servicio de descanso, que devuelve una imagen y adjunta ETag en respuesta.El servicio mantiene el hash de todos los archivos; si se cambia el archivo, el hash se actualiza.Funciona perfectamente en todos los navegadores modernos.Sí, lleva tiempo implementarlo, pero vale la pena.

La única excepción son los favicons.Por algunas razones, no funciona.No pude obligar al navegador a actualizar su caché desde el lado del servidor.ETags, Control de caché, Expires, encabezados Pragma, nada ayudó.

En este caso, parece que la única solución es agregar algún parámetro aleatorio/de versión a la URL.

Lo ideal sería agregar un botón/combinación de teclas/menú a cada página web con una opción para sincronizar el contenido.

Para hacerlo, debe realizar un seguimiento de los recursos que pueden necesitar sincronización y usar xhr para sondear las imágenes con una cadena de consulta dinámica o crear una imagen en tiempo de ejecución con src usando una cadena de consulta dinámica.Luego use un mecanismo de transmisión para notificar a todos los componentes de las páginas web que están utilizando el recurso para actualizar para usar el recurso con una consulta dinámica adjunta a su URL.

Un ejemplo ingenuo se ve así:

Normalmente, la imagen se muestra y se almacena en caché, pero si el usuario presionó el botón, se envía una solicitud xhr al recurso con una cadena de consulta de tiempo adjunta;Dado que se puede suponer que el tiempo es diferente en cada pulsación, se asegurará de que el navegador omita el caché, ya que no puede determinar si el recurso se genera dinámicamente en el lado del servidor en función de la consulta o si es estático. recurso que ignora la consulta.

El resultado es que puede evitar que todos sus usuarios lo bombardeen con solicitudes de recursos todo el tiempo, pero al mismo tiempo, permitir un mecanismo para que los usuarios actualicen sus recursos si sospechan que no están sincronizados.

<!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>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top