web-dev-qa-db-fra.com

Actualiser l'image avec une nouvelle dans la même URL

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?

284
QueueHammer

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);
}
2
QueueHammer

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.

304
Paolo Bergantino

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.

173
Aya

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.

6
BaroqueBobcat

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.

4
Edward KMETT

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')" />

3
Mahmoud

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);
}
1
Joel

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')" />
1
Codemaker
document.getElementById("img-id").src = document.getElementById("img-id").src

définir sa propre src en tant que src.

1
Hardik

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">
0
tinymothbrain
<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.

0
J Fields

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;
    }
0
Victor

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>
0
Timmmm