Estoy accediendo a un enlace en mi sitio que proporcionará una nueva imagen cada vez que se accede.
El problema con el que me encuentro es que si trato de cargar la imagen en segundo plano y luego actualizo la de la página, la imagen no cambia, aunque se actualiza cuando vuelvo a cargar la página.
var newImage = new Image();
newImage.src = "http://localhost/image.jpg";
function updateImage()
{
if(newImage.complete) {
document.getElementById("theText").src = newImage.src;
newImage = new Image();
number++;
newImage.src = "http://localhost/image/id/image.jpg?time=" + new Date();
}
setTimeout(updateImage, 1000);
}
Encabezados como FireFox los ve:
HTTP/1.x 200 OK
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Transfer-Encoding: chunked
Content-Type: image/jpeg
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Server: Microsoft-HTTPAPI/1.0
Date: Thu, 02 Jul 2009 23:06:04 GMT
Necesito forzar una actualización de solo esa imagen en la página. ¿Algunas ideas?
javascript
image
url
refresh
QueueHammer
fuente
fuente
Respuestas:
Intente agregar un rompedor de caché al final de la url:
Esto agregará la marca de tiempo actual automáticamente cuando esté creando la imagen, y hará que el navegador busque nuevamente la imagen en lugar de recuperar la que está en el caché.
fuente
'image.jpg?' + (+new Date())
Date.now()
para estoMath.random()
He visto muchas variaciones en las respuestas sobre cómo hacer esto, así que pensé en resumirlas aquí (además de agregar un cuarto método de mi propia invención):
(1) Agregue un parámetro de consulta único que revienta la caché a la URL, como:
Pros: 100% confiable, rápido y fácil de entender e implementar.
Contras: omite el almacenamiento en caché por completo, lo que significa retrasos innecesarios y el uso de ancho de banda siempre que la imagen no cambie entre las vistas. ¡Potencialmente llenará el caché del navegador (y cualquier caché intermedio) con muchas copias de exactamente la misma imagen! Además, requiere modificar la URL de la imagen.
Cuándo usar: se usa cuando la imagen cambia constantemente, como en el caso de una transmisión de cámara web en vivo. Si utiliza este método, asegúrese de servir las imágenes con
Cache-control: no-cache
encabezados HTTP. (A menudo, esto se puede configurar usando un archivo .htaccess). ¡De lo contrario, irás llenando cachés progresivamente con versiones antiguas de la imagen!(2) Agregue el parámetro de consulta a la URL que cambia solo cuando el archivo lo hace, por ejemplo:
(Ese es el código del lado del servidor PHP, pero el punto importante aquí es solo que una cadena de consulta ? M = [tiempo de última modificación del archivo] se agrega al nombre del archivo).
Pros: 100% confiable, rápido y fácil de entender e implementar, y conserva perfectamente las ventajas de almacenamiento en caché.
Contras: Requiere modificar la URL de la imagen. Además, un poco más de trabajo para el servidor: tiene que obtener acceso a la hora de última modificación del archivo. Además, requiere información del lado del servidor, por lo que no es adecuado para una solución exclusivamente del lado del cliente para buscar una imagen actualizada.
Cuándo usarlo: cuando desea almacenar en caché las imágenes, pero es posible que deba actualizarlas al final del servidor de vez en cuando sin cambiar el nombre del archivo. Y cuando puede asegurarse fácilmente de que se agrega la cadena de consulta correcta a cada instancia de imagen en su HTML.
(3) Sirva sus imágenes con el encabezado
Cache-control: max-age=0, must-revalidate
y agregue un identificador único de fragmento que revienta la memoria caché a la URL, como:La idea aquí es que el encabezado de control de caché coloca las imágenes en la memoria caché del navegador, pero inmediatamente las marca como obsoletas, de modo que y cada vez que se vuelven a mostrar, el navegador debe verificar con el servidor para ver si han cambiado. Esto garantiza que la memoria caché HTTP del navegador siempre devuelva la última copia de la imagen. Sin embargo, los navegadores a menudo reutilizarán una copia en memoria de una imagen si tienen una, y ni siquiera verificarán su caché HTTP en ese caso. Para evitar esto, se utiliza un identificador de fragmento: la comparación de las imágenes en memoria
src
incluye el identificador de fragmento, pero se elimina antes de consultar el caché HTTP. (Entonces, por ejemplo,image.jpg#A
yimage.jpg#B
ambos pueden mostrarse desde laimage.jpg
entrada en el caché HTTP del navegador, peroimage.jpg#B
nunca se mostraría utilizando datos de imagen retenidos en la memoria de laimage.jpg#A
última vez que se mostró).Pros: hace un uso adecuado de los mecanismos de almacenamiento en caché HTTP y utiliza imágenes almacenadas en caché si no han cambiado. Funciona para servidores que se ahogan en una cadena de consulta agregada a una URL de imagen estática (ya que los servidores nunca ven identificadores de fragmentos, son para uso exclusivo de los navegadores).
Contras: se basa en el comportamiento algo dudoso (o al menos mal documentado) de los navegadores, con respecto a las imágenes con identificadores de fragmentos en sus URL (sin embargo, lo he probado con éxito en FF27, Chrome33 e IE11). Todavía envía una solicitud de revalidación al servidor para cada vista de imagen, lo que puede ser excesivo si las imágenes solo cambian raramente y / o la latencia es un gran problema (ya que debe esperar la respuesta de revalidación incluso cuando la imagen en caché aún es buena) . Requiere modificar las URL de las imágenes.
Cuándo usarlo: use cuándo las imágenes pueden cambiar con frecuencia, o si el cliente necesita actualizarlas de manera intermitente sin la participación del script del lado del servidor, pero donde aún desea la ventaja del almacenamiento en caché. Por ejemplo, sondear una cámara web en vivo que actualiza una imagen de forma irregular cada pocos minutos. Alternativamente, use en lugar de (1) o (2) si su servidor no permite cadenas de consulta en URL de imágenes estáticas.
(4) Actualice por la fuerza una imagen en particular usando Javascript, primero cargándola en un oculto
<iframe>
y luego llamandolocation.reload(true)
al iframecontentWindow
.Los pasos son:
Cargue la imagen para actualizarla en un iframe oculto. Este es solo un paso de configuración: si lo desea, puede realizar la actualización real con mucha anticipación. ¡Ni siquiera importa si la imagen no se carga en esta etapa!
Una vez hecho esto, deje en blanco todas las copias de esa imagen en su (s) página (s) o en cualquier lugar en cualquier nodo DOM (incluso los que están fuera de la página almacenados en variables de JavaScript). Esto es necesario porque el navegador puede mostrar la imagen de una copia en memoria obsoleta (IE11 hace esto especialmente): debe asegurarse de que se borran todas las copias en memoria antes de actualizar la caché HTTP. Si otro código de JavaScript se ejecuta de forma asincrónica, es posible que también deba evitar que ese código cree nuevas copias de la imagen que debe actualizarse mientras tanto.
Llamada
iframe.contentWindow.location.reload(true)
. Lastrue
fuerzas de un bypass caché, recarga directamente desde el servidor y sobrescribir la copia en caché existente.Una vez que haya terminado de volver a cargar, restaure las imágenes en blanco. ¡Ahora deberían mostrar la versión nueva del servidor!
Para imágenes del mismo dominio, puede cargar la imagen en el iframe directamente. Para las imágenes entre dominios, debe cargar una página HTML de su dominio que contenga la imagen en una
<img>
etiqueta; de lo contrario, recibirá un error de "Acceso denegado" al intentar llamariframe.contentWindow.reload(...)
.Pros: ¡ Funciona igual que la función image.reload () que desearía que tuviera el DOM! Permite que las imágenes se almacenen en caché normalmente (incluso con fechas de vencimiento futuras si así lo desea, evitando así la revalidación frecuente). Le permite actualizar una imagen en particular sin alterar las URL de esa imagen en la página actual o en cualquier otra página, utilizando solo el código del lado del cliente.
Contras: se basa en Javascript. No se garantiza al 100% que funcione correctamente en todos los navegadores (aunque lo he probado con éxito en FF27, Chrome33 e IE11). Muy complicado en relación con los otros métodos.
Cuándo usarlo: cuando tiene una colección de imágenes básicamente estáticas que le gustaría almacenar en caché, pero aún necesita poder actualizarlas ocasionalmente y obtener comentarios visuales inmediatos de que la actualización se realizó. (Especialmente cuando la actualización de toda la página del navegador no funcionaría, como en algunas aplicaciones web creadas en AJAX, por ejemplo). Y cuando los métodos (1) - (3) no son factibles porque (por cualquier razón) no puede cambiar todas las URL que podrían mostrar la imagen que necesita actualizar. (Tenga en cuenta que al usar esos 3 métodos, la imagen se actualizará, pero si otra página intenta mostrar esa imagen sin la cadena de consulta adecuada o el identificador de fragmento, puede mostrar una versión anterior).
Los detalles de implementar esto de una manera robusta y flexible se dan a continuación:
Supongamos que su sitio web contiene un .gif en blanco de 1x1 píxeles en la ruta URL
/img/1x1blank.gif
, y también tiene el siguiente script PHP de una línea (solo se requiere para aplicar la actualización forzada a las imágenes entre dominios , y se puede reescribir en cualquier lenguaje de script del lado del servidor , por supuesto) en la ruta URL/echoimg.php
:Entonces, aquí hay una implementación realista de cómo podría hacer todo esto en Javascript. Parece un poco complicado, pero hay muchos comentarios, y la función importante es forceImgReload (): las dos primeras imágenes en blanco y en blanco, y deben estar diseñadas para funcionar de manera eficiente con su propio HTML, así que codifíquelas como funciona mejor para ti; Muchas de las complicaciones en ellos pueden ser innecesarias para su sitio web
Luego, para forzar una actualización de una imagen ubicada en el mismo dominio que su página, puede hacer lo siguiente:
Para actualizar una imagen desde otro lugar (dominio cruzado):
Una aplicación más avanzada podría ser volver a cargar una imagen después de cargar una nueva versión en su servidor, preparando la etapa inicial del proceso de recarga simultáneamente con la carga, para minimizar el retraso de recarga visible para el usuario. Si está cargando a través de AJAX, y el servidor está devolviendo una matriz JSON muy simple [éxito, ancho, altura], entonces su código podría verse así:
Una nota final: aunque este tema trata sobre imágenes, también se aplica potencialmente a otros tipos de archivos o recursos. Por ejemplo, evitar el uso de secuencias de comandos obsoletas o archivos CSS, o quizás incluso actualizar documentos PDF actualizados (usando (4) solo si está configurado para abrir en el navegador). El método (4) puede requerir algunos cambios en el javascript anterior, en estos casos.
fuente
image.jpg#123
aimage.jpg#124
(o lo que sea, siempre que cambie el bit después del '#'). ¿Podría aclarar qué es lo que está recargando y por qué?contentWindow
través de javascript para hacer lareload(true)
llamada que es la parte crítica del método ... así que no, método (4 ) no funcionará para contenido entre dominios. Bien descrito; Actualizaré los "Contras" para incluir eso.Como alternativa a ...
...parece que...
... es suficiente para engañar al caché del navegador sin pasar por alto ningún caché ascendente, suponiendo que haya devuelto los
Cache-Control
encabezados correctos . Aunque puedes usar ...... pierde los beneficios de los encabezados
If-Modified-Since
oIf-None-Match
, así que algo así como ...... debería evitar que el navegador vuelva a descargar la imagen completa si no ha cambiado realmente. Probado y trabajando en IE, Firefox y Chrome. Molesto, falla en Safari a menos que uses ...
... aunque esto puede ser preferible a llenar cachés en sentido ascendente con cientos de imágenes idénticas, especialmente cuando se ejecutan en su propio servidor. ;-)
Actualización (28-09-2014): hoy en día parece que también
Cache-Control: no-store
es necesario para Chrome.fuente
src
atributo completo , por lo que agregar un identificador de fragmento único garantiza que la imagen no se extraiga simplemente de la memoria. Pero los identificadores de fragmentos no se envían como parte de las solicitudes HTTP, por lo que el caché HTTP normal se utilizará de forma normal. Por eso funciona esta técnica.Cache-Control: max-age=0, must-revalidate
es bueno para mi?newImage.src = "http://localhost/image.jpg#" + i++;
Después de crear la nueva imagen, ¿está eliminando la imagen anterior del DOM y reemplazándola por la nueva?
Podrías capturar nuevas imágenes en cada llamada a UpdateImage, pero no agregarlas a la página.
Hay varias formas de hacerlo. Algo como esto funcionaría.
Después de que eso funcione, si todavía hay problemas, es probable que se trate de un problema de almacenamiento en caché, como se menciona en las otras respuestas.
fuente
Una respuesta es agregar hackear algunos parámetros de obtención de consultas como se ha sugerido.
Una mejor respuesta es emitir un par de opciones adicionales en su encabezado HTTP.
Al proporcionar una fecha en el pasado, el navegador no la almacenará en caché.
Cache-Control
se agregó en HTTP / 1.1 y la etiqueta de revalidar debe indicar que los servidores proxy nunca deben mostrar una imagen antigua incluso en circunstancias atenuantes, y estoPragma: no-cache
no es realmente necesario para los navegadores / cachés modernos actuales, pero puede ayudar con algunas implementaciones antiguas rotas y mal hechas.fuente
Tenía un requisito: 1) no puedo agregar ninguno
?var=xx
a la imagen 2) debería funcionar entre dominiosRealmente me gusta la opción # 4 en esta respuesta con una pero:
Mi manera rápida y sucia es:
iframe.contentWindow.location.reload(true);
Aquí está
Sí, lo sé, setTimeout ... Tienes que cambiar eso a los eventos de carga adecuados.
fuente
Luego a continuación en algunos javascript
Y lo que esto hace es que, cuando se carga la imagen, programa que se vuelva a cargar en 1 segundo. Estoy usando esto en una página con cámaras de seguridad para el hogar de diferentes tipos.
fuente
Lo que terminé haciendo fue que el servidor asignara cualquier solicitud de una imagen en ese directorio a la fuente que estaba tratando de actualizar. Luego hice que mi temporizador agregara un número al final del nombre para que el DOM lo viera como una nueva imagen y lo cargara.
P.ej
solicitará el mismo código de generación de imágenes pero se verá como imágenes diferentes para el navegador.
fuente
fuente
../showImage.phpFri May 01 2015 17:34:18 GMT+0200 (Mitteleuropäische Sommerzeit)
sea un nombre de archivo válido ... Al menos esto es lo que intenta cargar ...path='../showImage.php';
apath='../showImage.php?';
establece su propio src como su src.
fuente
Intente usar una cadena de consulta sin valor para convertirla en una url única:
fuente
En gran medida basado en el código # 4 de Doin, los siguientes simplifica ejemplo que el código de un gran bits utilizando
document.write
en lugar desrc
en eliframe
de apoyar CORS. También solo se enfoca en destruir la memoria caché del navegador, no en recargar cada imagen en la página.A continuación está escrito
typescript
y utiliza la biblioteca de promesaangular
$ q , solo para su información, pero debería ser lo suficientemente fácil de portar a JavaScript vainilla. El método está destinado a vivir dentro de una clase mecanografiada.Devuelve una promesa que se resolverá cuando el iframe haya completado la recarga. No muy probado, pero funciona bien para nosotros.
fuente
+ encodeURI(src) +
para escapar correctamentesrc
en eliframe
.El siguiente código es útil para actualizar la imagen cuando se hace clic en un botón.
fuente
Resolví este problema enviando los datos de vuelta a través de un servlet.
Luego, desde la página, simplemente le da el servlet con algunos parámetros para obtener el archivo de imagen correcto.
fuente
Aquí está mi solución. Es muy simple. La programación del marco podría ser mejor.
fuente
No hay necesidad de
new Date().getTime()
travesuras. Puede engañar al navegador teniendo una imagen ficticia invisible y usando jQuery .load (), luego creando una nueva imagen cada vez:fuente
Solución simple: agregue este encabezado a la respuesta:
Por qué esto funciona se explica claramente en esta página autorizada: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
También explica por qué
no-cache
no funciona.Otras respuestas no funcionan porque:
Caching.delete
se trata de un nuevo caché que puede crear para el trabajo fuera de línea, consulte: https://web.dev/cache-api-quick-guide/Los fragmentos que usan un # en la URL no funcionan porque el # le dice al navegador que no envíe una solicitud al servidor.
Un cache-buster con una parte aleatoria agregada a la url funciona, pero también llenará el caché del navegador. En mi aplicación, quería descargar una imagen de 5 MB cada pocos segundos desde una cámara web. Le tomará solo una hora o menos congelar completamente su PC. Todavía no sé por qué la memoria caché del navegador no se limita a un máximo razonable, pero esto definitivamente es una desventaja.
fuente
Mejoré el script de AlexMA para mostrar mi cámara web en una página web que carga periódicamente una nueva imagen con el mismo nombre. Tuve problemas de que a veces la imagen parpadeaba debido a una imagen rota o una imagen cargada no completa (arriba). Para evitar el parpadeo, verifico la altura natural de la imagen porque el tamaño de la imagen de mi cámara web no cambió. Solo si la altura de la imagen cargada se ajusta a la altura de la imagen original, la imagen completa se mostrará en la página.
fuente
Usé el siguiente concepto de primero vincular la imagen con una URL falsa (buffer) y luego vincularla con la URL válida.
De esta manera, estoy obligando al navegador a actualizarse con una URL válida.
fuente