J'accède à un lien sur mon site qui fournira une nouvelle image à chaque accès.
Le problème que je rencontre est que si j'essaie de charger l'image en arrière-plan, puis de la mettre à jour sur la page, l'image ne change pas - bien qu'elle soit mise à jour lorsque je recharge la page.
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);
}
En-têtes tels que FireFox les voit:
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
Je dois forcer un rafraîchissement de cette image sur la page. Des idées?
J'ai fini par demander au serveur de mapper toute demande d'image dans ce répertoire avec la source que j'essayais de mettre à jour. J'ai ensuite demandé à ma minuterie d'ajouter un numéro à la fin du nom pour que le DOM la voit comme une nouvelle image et la charge.
Par exemple.
http://localhost/image.jpg
//and
http://localhost/image01.jpg
demandera le même code de génération d'image, mais il ressemblera à différentes images pour le navigateur.
var newImage = new Image();
newImage.src = "http://localhost/image.jpg";
var count = 0;
function updateImage()
{
if(newImage.complete) {
document.getElementById("theText").src = newImage.src;
newImage = new Image();
newImage.src = "http://localhost/image/id/image" + count++ + ".jpg";
}
setTimeout(updateImage, 1000);
}
Essayez d'ajouter un cachebreaker à la fin de l'URL:
newImage.src = "http://localhost/image.jpg?" + new Date().getTime();
Cela ajoutera automatiquement l’horodatage actuel lors de la création de l’image et incitera le navigateur à rechercher l’image au lieu de récupérer celle qui se trouve dans le cache.
Comme alternative à ...
newImage.src = "http://localhost/image.jpg?" + new Date().getTime();
...Il paraît que...
newImage.src = "http://localhost/image.jpg#" + new Date().getTime();
... est suffisant pour tromper le cache du navigateur sans contourner les caches en amont, en supposant que vous ayez renvoyé les en-têtes Cache-Control
corrects. Bien que vous puissiez utiliser ...
Cache-Control: no-cache, must-revalidate
... vous perdez les avantages des en-têtes If-Modified-Since
ou If-None-Match
, donc quelque chose comme ...
Cache-Control: max-age=0, must-revalidate
... devrait empêcher le navigateur de télécharger à nouveau toute l'image si elle n'a pas réellement changé. Testé et fonctionnant sur IE, Firefox et Chrome. Malheureusement, il échoue sous Safari, sauf si vous utilisez ...
Cache-Control: no-store
... bien que cela puisse être préférable au remplissage de caches en amont avec des centaines d'images identiques, en particulier lorsqu'elles s'exécutent sur votre propre serveur. ;-)
Mise à jour (2014-09-28): De nos jours, il semble que Cache-Control: no-store
soit également nécessaire pour Chrome.
Après avoir créé la nouvelle image, supprimez-vous l'ancienne image du DOM et remplacez-la par la nouvelle?
Vous pourriez capturer de nouvelles images à chaque appel de updateImage, sans les ajouter à la page.
Il y a plusieurs façons de le faire. Quelque chose comme ça fonctionnerait.
function updateImage()
{
var image = document.getElementById("theText");
if(image.complete) {
var new_image = new Image();
//set up the new image
new_image.id = "theText";
new_image.src = image.src;
// insert new image and remove old
image.parentNode.insertBefore(new_image,image);
image.parentNode.removeChild(image);
}
setTimeout(updateImage, 1000);
}
Une fois que cela fonctionne, s’il ya encore des problèmes, il s’agit probablement d’un problème de mise en cache, comme le montrent les autres réponses.
Une solution consiste à ajouter de manière astucieuse un paramètre de requête get, comme cela a été suggéré.
Une meilleure réponse consiste à émettre quelques options supplémentaires dans votre en-tête HTTP.
Pragma: no-cache
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Cache-Control: no-cache, must-revalidate
En fournissant une date dans le passé, elle ne sera pas mise en cache par le navigateur. Cache-Control
a été ajouté dans HTTP/1.1 et la balise must-revalidate indique que les mandataires ne doivent jamais servir une vieille image, même dans des circonstances atténuantes, et que Pragma: no-cache
n'est pas vraiment nécessaire pour les navigateurs/caches modernes, mais peut aider avec certains fichiers crus mises en œuvre.
function reloadImage(imageId)
{
path = '../showImage.php?cache='; //for example
imageObject = document.getElementById(imageId);
imageObject.src = path + (new Date()).getTime();
}
<img src='../showImage.php' id='myimage' />
<br/>
<input type='button' onclick="reloadImage('myimage')" />
Essayez d’utiliser une chaîne de requête sans valeur pour en faire une URL unique:
function updateImage()
{
if(newImage.complete) {
document.getElementById("theText").src = newImage.src;
newImage = new Image();
number++;
newImage.src = "http://localhost/image.jpg?" + new Date();
}
setTimeout(updateImage, 1000);
}
Le code suivant est utile pour actualiser l'image lorsqu'un clic est effectué sur un bouton.
function reloadImage(imageId) {
imgName = 'vishnu.jpg'; //for example
imageObject = document.getElementById(imageId);
imageObject.src = imgName;
}
<img src='vishnu.jpg' id='myimage' />
<input type='button' onclick="reloadImage('myimage')" />
document.getElementById("img-id").src = document.getElementById("img-id").src
définir sa propre src en tant que src.
J'ai résolu ce problème en renvoyant les données via un servlet.
response.setContentType("image/png");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache, must-revalidate");
response.setDateHeader("Expires", 0);
BufferedImage img = ImageIO.read(new File(imageFileName));
ImageIO.write(img, "png", response.getOutputStream());
Ensuite, à partir de la page, vous fournissez simplement la servlet avec quelques paramètres pour récupérer le fichier image correct.
<img src="YourServlet?imageFileName=imageNum1">
<img src='someurl.com/someimage.ext' onload='imageRefresh(this, 1000);'>
Puis ci-dessous dans certains javascript
<script language='javascript'>
function imageRefresh(img, timeout) {
setTimeout(function() {
var d = new Date;
var http = img.src;
if (http.indexOf("&d=") != -1) { http = http.split("&d=")[0]; }
img.src = http + '&d=' + d.getTime();
}, timeout);
}
</script>
Et donc, lorsque l’image est chargée, elle est programmée pour être rechargée en 1 seconde. J'utilise cela sur une page avec des caméras de sécurité à domicile de type différent.
Fortement basé sur le code n ° 4 de Doin, l'exemple ci-dessous simplifie grandement ce code en utilisant document.write
au lieu de src
dans iframe
pour prendre en charge CORS. De plus, concentrez-vous uniquement sur la suppression du cache du navigateur, pas sur le rechargement de chaque image de la page.
Le texte ci-dessous est écrit dans TypeScript
et utilise la angular
$ q bibliothèque de promesses, fyi seulement, mais devrait être assez facile à porter en javascript dans Vanilla. La méthode est censée vivre à l'intérieur d'une classe TypeScript.
Renvoie une promesse qui sera résolue lorsque l'iframe aura terminé le rechargement. Pas lourdement testé, mais fonctionne bien pour nous.
mmForceImgReload(src: string): ng.IPromise<void> {
var deferred = $q.defer<void>();
var iframe = window.document.createElement("iframe");
var firstLoad = true;
var loadCallback = (e) => {
if (firstLoad) {
firstLoad = false;
iframe.contentWindow.location.reload(true);
} else {
if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
deferred.resolve();
}
}
iframe.style.display = "none";
window.parent.document.body.appendChild(iframe);
iframe.addEventListener("load", loadCallback, false);
iframe.addEventListener("error", loadCallback, false);
var doc = iframe.contentWindow.document;
doc.open();
doc.write('<html><head><title></title></head><body><img src="' + src + '"></body></html>');
doc.close();
return deferred.promise;
}
Voici ma solution. C'est très simple. La planification des images pourrait être meilleure.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Image Refresh</title>
</head>
<body>
<!-- Get the initial image. -->
<img id="frame" src="frame.jpg">
<script>
// Use an off-screen image to load the next frame.
var img = new Image();
// When it is loaded...
img.addEventListener("load", function() {
// Set the on-screen image to the same source. This should be instant because
// it is already loaded.
document.getElementById("frame").src = img.src;
// Schedule loading the next frame.
setTimeout(function() {
img.src = "frame.jpg?" + (new Date).getTime();
}, 1000/15); // 15 FPS (more or less)
})
// Start the loading process.
img.src = "frame.jpg?" + (new Date).getTime();
</script>
</body>
</html>