Deshabilitar la caché para algunas imágenes

113

Genero algunas imágenes usando una lib de PHP.

A veces, el navegador no carga el nuevo archivo generado.

¿Cómo puedo desactivar la caché solo para las imágenes creadas dinámicamente por mí?

Nota: tengo que usar el mismo nombre para las imágenes creadas a lo largo del tiempo.

dole doug
fuente

Respuestas:

233

Una solución común y simple a este problema que parece un truco pero que es bastante portátil es agregar una cadena de consulta generada aleatoriamente a cada solicitud de la imagen dinámica.

Así por ejemplo -

<img src="image.png" />

Se convertiría

<img src="image.png?dummy=8484744" />

O

<img src="image.png?dummy=371662" />

Desde el punto de vista del servidor web se accede al mismo archivo, pero desde el punto de vista del navegador no se puede realizar el almacenamiento en caché.

La generación de números aleatorios puede ocurrir en el servidor cuando se entrega la página (solo asegúrese de que la página no esté almacenada en caché ...) o en el cliente (usando JavaScript).

Deberá verificar si su servidor web puede hacer frente a este truco.

Hexágono
fuente
87
En lugar de números aleatorios, utilice la marca de tiempo en la que cambiaron los datos o un número de versión de los datos reflejados.
Lunes
19
Tenga en cuenta: en realidad, no impide que el navegador almacene en caché la imagen, solo evita ver la imagen en caché. Aplicar encabezados adecuados a su imagen es la mejor manera en mi humilde opinión (consulte la solución de lhunath a continuación). Dado que de esta manera también llena el caché innecesariamente con imágenes que no desea almacenar en caché con el costo de causar menos espacio en el caché para las cosas que realmente desea almacenar en caché.
Jos
Creo que este artículo explica la razón de tal comportamiento.
Metalcoder
1
esto realmente no funciona, la imagen debe limpiarse de otra manera (generalmente en el recorte de la imagen, la imagen permanece igual)
Ben
44

Las estrategias de almacenamiento en caché del navegador se pueden controlar mediante encabezados HTTP. Recuerda que en realidad son solo una pista. Dado que los navegadores son terriblemente inconsistentes en este (y en cualquier otro) campo, necesitará varios encabezados para obtener el efecto deseado en una variedad de navegadores.

header ("Pragma-directive: no-cache");
header ("Cache-directive: no-cache");
header ("Cache-control: no-cache");
header ("Pragma: no-cache");
header ("Expires: 0");
lhunath
fuente
1
esto se aplicará a toda la página ... ¿No puedo deshabilitar la caché para una sola imagen (una imagen específica de esa página)?
dole doug
5
@Thorpe: se aplica a las respuestas HTTP. Lo que está contenido en la respuesta es irrelevante. Ya sean datos de imagen, datos HTML o cualquier otra cosa. Si no funcionó, probablemente no lo hizo bien. Verifique los encabezados HTTP en su respuesta para ver si se han asignado correctamente.
lhunath
Ojalá esto funcionara ... Chrome no tiene ningún problema, pero Firefox 14 e IE 8 se niegan a actualizar las imágenes incluso con los encabezados anteriores enviados. Esta habría sido una solución mucho más limpia que agregar algunos parámetros arbitrarios a la cadena de consulta. suspiro
Pawel Krakowiak
2
@PawelKrakowiak Tenga en cuenta que agregar encabezados no funcionará para imágenes que ya están almacenadas en caché , ya que el navegador ni siquiera pregunta al servidor sobre ellas y, por lo tanto, nunca verá los encabezados. Funcionarán para cualquier solicitud de imagen realizada después de que las haya agregado.
lhunath
2
Esta solución está destinada a programadores, no a diseñadores web. Pensé que señalaría eso porque uno no puede simplemente abrir una imagen y agregar encabezados a una imagen, a menos que ellos mismos estén generando la imagen en un lenguaje de programación y esto parece confundir a los comentaristas.
Bruce
13

Si necesita hacerlo dinámicamente en el navegador usando javascript, aquí hay un ejemplo ...

<img id=graph alt="" 
  src="http://www.kitco.com/images/live/gold.gif" 
  />

<script language="javascript" type="text/javascript">
    var d = new Date(); 
    document.getElementById("graph").src = 
      "http://www.kitco.com/images/live/gold.gif?ver=" + 
       d.getTime();
</script>
Anton Swanevelder
fuente
12

La solución 1 no es excelente. Funciona, pero agregar cadenas de consulta aleatorias o con marca de tiempo al final de sus archivos de imagen hará que el navegador vuelva a descargar y almacene en caché cada versión de cada imagen, cada vez que se carga una página, independientemente del clima en que la imagen haya cambiado o no. en el servidor.

La solución 2 es inútil. Agregar nocacheencabezados a un archivo de imagen no solo es muy difícil de implementar, sino que es completamente impráctico porque requiere que prediga cuándo será necesario con anticipación , la primera vez que cargue una imagen que crea que podría cambiar en algún momento en el futuro. .

Entra Etags ...

La mejor manera absoluta que he encontrado para resolver esto es usar ETAGS dentro de un archivo .htaccess en su directorio de imágenes. Lo siguiente le dice a Apache que envíe un hash único al navegador en los encabezados del archivo de imagen. Este hash solo cambia cuando se modifica el archivo de imagen y este cambio hace que el navegador vuelva a cargar la imagen la próxima vez que se solicite.

<FilesMatch "\.(jpg|jpeg)$">
FileETag MTime Size
</FilesMatch>
cronoklee
fuente
11

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

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

primero.

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

La solución a este problema fue:

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

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

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

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 la caché para esa imagen por completo) Por lo tanto, para servir la imagen en caché desde el navegador HASTA que haya un cambio en el uso del archivo de imagen:

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

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

Tarik
fuente
4

Sé que este tema es antiguo, pero se ubica muy bien en Google. Descubrí que poner esto en tu encabezado funciona bien;

<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">
Dimitri Visser
fuente
Desafortunadamente, los navegadores modernos están ignorando estas directivas, por lo tanto, esta solución podría funcionar solo en algunos navegadores, además, deshabilitará el caché para todo, no solo para imágenes específicas
ZioCain
4

Solo estaba buscando una solución a esto, y las respuestas anteriores no funcionaron en mi caso (y no tengo una reputación suficiente para comentarlas). Resulta que, al menos para mi caso de uso y el navegador que estaba usando (Chrome en OSX), lo único que parecía evitar el almacenamiento en caché era:

Cache-Control = 'no-store'

Para completar, ahora estoy usando los 3 de 'no-cache, no-store, must-revalidate'

Entonces, en mi caso (sirviendo imágenes generadas dinámicamente desde Flask en Python), tuve que hacer lo siguiente para, con suerte, trabajar en tantos navegadores como sea posible ...

def make_uncached_response(inFile):
    response = make_response(inFile)
    response.headers['Pragma-Directive'] = 'no-cache'
    response.headers['Cache-Directive'] = 'no-cache'
    response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
    response.headers['Pragma'] = 'no-cache'
    response.headers['Expires'] = '0'
    return response
marca
fuente
Sólo poner no-store en la respuesta fue suficiente para conseguir que funcione para mí
scourge192
No es solo en Chrome, también para Firefox. Ahora parece ser un estándar: developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control (consulte la sección " Prevención del almacenamiento en caché ").
Gino Mempin
3

Cambiar la fuente de la imagen es la solución. De hecho, puede hacer esto agregando una marca de tiempo o un número aleatorio a la imagen.

Mejor sería agregar una suma de verificación de, por ejemplo, los datos que representa la imagen. Esto habilita el almacenamiento en caché cuando sea posible.

Stefan van Gastel
fuente
1

Agreguemos otra solución al grupo.

Agregar una cadena única al final es una solución perfecta.

example.jpg?646413154

La siguiente solución amplía este método y proporciona tanto la capacidad de almacenamiento en caché como la obtención de una nueva versión cuando se actualiza la imagen.

Cuando se actualice la imagen, se cambiará la hora del archivo .

<?php
$filename = "path/to/images/example.jpg";
$filemtime = filemtime($filename);
?>

Ahora genere la imagen:

<img src="images/example.jpg?<?php echo $filemtime; ?>" >
Daniel
fuente
1
Eso es lo que usé debido a la validez del almacenamiento en caché.
gene
1

Tuve este problema y lo supere así.

var newtags='<div class="addedimage"><h5>preview image</h5><img src="'+one+'?nocache='+Math.floor(Math.random() * 1000)+'"></div>';
Jordania Georgiadis
fuente
0

He usado esto para resolver mi problema similar ... mostrar un contador de imágenes (de un proveedor externo). No siempre se actualizaba correctamente. Y después de agregar un parámetro aleatorio, todo funciona bien :)

Agregué una cadena de fecha para asegurar la actualización al menos cada minuto.

código de muestra (PHP):

$output .= "<img src=\"http://xy.somecounter.com/?id=1234567890&".date(ymdHi)."\" alt=\"somecounter.com\" style=\"border:none;\">";

Eso da como resultado un srcenlace como:

http://xy.somecounter.com/?id=1234567890&1207241014
Pinoccio
fuente
0

Si tiene una URL de imagen codificada, por ejemplo: http://example.com/image.jpg , puede usar php para agregar encabezados a su imagen.

Primero tendrás que hacer que apache procese tu jpg como php. Vea aquí: ¿Es posible ejecutar PHP con la extensión file.php.jpg?

Cargue la imagen (imagecreatefromjpeg) del archivo y luego agregue los encabezados de las respuestas anteriores. Utilice el encabezado de la función php para agregar los encabezados.

Luego genere la imagen con la función imagejpeg.

Tenga en cuenta que es muy inseguro permitir que php procese imágenes jpg. Además, tenga en cuenta que no he probado esta solución, por lo que depende de usted hacer que funcione.

Sam Sam
fuente
-1

Sencillo, envíe una ubicación de encabezado.

Mi sitio contiene una imagen, y después de cargar la imagen, no hay cambios, luego agrego este código:

<?php header("Location: pagelocalimage.php"); ?>

Funciona para mi.

Programador
fuente