Question

Arrière-plan

J'écris et utilise un outil très simple de gestion de contenu basé sur CGI (Perl) pour deux sites Web pro bono. Il fournit à l'administrateur de site Web des formulaires HTML pour les événements dans lesquels il remplit les champs (date, lieu, titre, description, liens, etc.) et les enregistre. Sur ce formulaire, j'autorise l'administrateur à télécharger une image liée à l'événement. Sur la page HTML affichant le formulaire, je montre également un aperçu de l'image téléchargée (balise HTML img).

Le problème

Le problème survient lorsque l'administrateur souhaite modifier l'image. Il lui suffirait de cliquer sur & "Parcourir &"; bouton, choisissez une nouvelle image et appuyez sur ok. Et cela fonctionne bien.

Une fois l'image téléchargée, mon CGI d’arrière-plan gère le téléchargement et recharge correctement le formulaire.

Le problème est que l'image affichée n'est pas actualisée . L'ancienne image est toujours affichée, même si la base de données contient la bonne image. Je l'ai réduit au fait que l'image est cachée dans le navigateur Web. Si l’administrateur appuie sur le bouton RELOAD dans Firefox / Explorer / Safari, tout est rafraîchi et la nouvelle image s’affiche.

Ma solution - Ne fonctionne pas

J'essaie de contrôler le cache en écrivant une instruction HTTP Expires dont la date est très éloignée.

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

N'oubliez pas que je suis du côté administratif et que le chargement des pages prend un peu plus de temps, peu m'importe qu'elles soient toujours périmées.

Mais cela ne fonctionne pas non plus.

Notes

Lors du téléchargement d'une image, son nom de fichier n'est pas conservé dans la base de données. Il est renommé Image.jpg (pour simplifier les choses lors de son utilisation). Lors du remplacement de l'image existante par une nouvelle image, le nom ne change pas non plus. Seul le contenu du fichier image change.

Le serveur Web est fourni par le service d’hébergement / le fournisseur de services Internet. Il utilise Apache.

Question

Existe-t-il un moyen de forcer le navigateur Web à ne PAS mettre en cache les éléments de cette page, pas même les images?

Je jongle avec l'option consistant à & sauvegarder le nom de fichier & "; avec la base de données. De cette façon, si l'image est modifiée, le src de la balise IMG sera également modifié. Cependant, cela nécessite beaucoup de changements sur tout le site et je préfère ne pas le faire si j'ai une meilleure solution. De plus, cela ne fonctionnera toujours pas si la nouvelle image téléchargée porte le même nom (par exemple, l’image est un peu reportée et ré-téléchargée).

Était-ce utile?

La solution

Armin Ronacher a la bonne idée. Le problème est que des chaînes aléatoires peuvent entrer en collision. Je voudrais utiliser:

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

Où " 1222259157.415 " est l'heure actuelle sur le serveur.
Générer du temps avec Javascript avec performance.now() ou avec Python avec time.time()

Autres conseils

Solution simple: associez une chaîne de requête aléatoire à l'image:

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

Ce que dit la RFC HTTP:

Cache-Control: no-cache

Mais cela ne fonctionne pas très bien:)

J'utilise la fonction de modification de l'heure du fichier de PHP , par exemple:

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

Si vous modifiez l'image, la nouvelle image est utilisée plutôt que celle mise en cache, car son horodatage modifié est différent.

Je voudrais utiliser:

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

où & "; 20130910043254 &"; est le moment de la modification du fichier.

  

Lors du téléchargement d'une image, son nom de fichier n'est pas conservé dans la base de données. Il est renommé Image.jpg (pour simplifier les choses lors de son utilisation). Lors du remplacement de l'image existante par une nouvelle image, le nom ne change pas non plus. Seul le contenu du fichier image change.

Je pense qu’il existe deux types de solutions simples: 1) celles qui viennent à l’esprit en premier (solutions simples, parce qu’elles sont faciles à trouver), 2) celles avec lesquelles vous vous retrouvez après avoir réfléchi (parce sont faciles à utiliser). Apparemment, vous ne bénéficierez pas toujours si vous choisissez de réfléchir. Mais la deuxième option est plutôt sous-estimée, je crois. Imaginez pourquoi php est si populaire;)

Vous pouvez écrire un script proxy pour le traitement des images - cela représente cependant un peu plus de travail. Quelque chose aime ça:

HTML:

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

Script:

// 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 fait, les en-têtes sans cache ou les nombres aléatoires dans image src devraient suffire, mais puisque nous voulons être à l'abri des balles.

Je suis un NOUVEAU codeur, mais voici ce que j'ai proposé pour empêcher le navigateur de mettre en cache et de conserver les vues de ma webcam:

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

Vous ne savez pas ce qui fonctionne sur le navigateur, mais cela fonctionne pour certains: IE: Fonctionne lorsque la page Web est actualisée et lorsque le site Web est revisité (sans actualisation). CHROME: Ne fonctionne que lorsque la page Web est actualisée (même après une visite ultérieure). SAFARI et iPad: ça ne marche pas, je dois vider l’historique &; Données Web.

Des idées sur SAFARI / iPad?

utilisez Class = & "NO-CACHE &";

.

exemple html:

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

Résultat: src = " images / img1.jpg " = > src = & "images / img1.jpg? a = 0.08749723793963926 &";

  

Lors du téléchargement d'une image, son nom de fichier n'est pas conservé dans la base de données. Il est renommé Image.jpg (pour simplifier les choses lors de son utilisation).

Modifiez cela et vous avez résolu votre problème. J'utilise des horodatages, comme avec les solutions proposées ci-dessus: Image - & Lt; horodatage & Gt; .jpg

Vraisemblablement, tous les problèmes que vous éviterez en conservant le même nom de fichier pour l'image peuvent être résolus, mais vous ne dites pas ce qu'ils sont.

J'ai vérifié toutes les réponses sur le Web et la meilleure d'entre elles semblait être: (ce n'est pas le cas)

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

au début.

Toutefois, si vous ajoutez le paramètre cache = none (qui est un mot statique " none "), le navigateur reste chargé à partir du cache.

La solution à ce problème était la suivante:

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

où vous avez essentiellement ajouté un horodatage Unix pour rendre le paramètre dynamique et l'absence de cache, cela a fonctionné.

Cependant, mon problème était un peu différent: Je chargeais à la volée l'image du graphique php généré et contrôlais la page avec les paramètres $ _GET. Je souhaitais que l'image soit lue dans le cache lorsque le paramètre d'URL GET reste inchangé et ne mette pas en cache lorsque les paramètres de GET changent.

Pour résoudre ce problème, j'avais besoin de hacher $ _GET mais comme c'est un tableau, voici la solution:

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

Modifier :

Bien que la solution ci-dessus fonctionne correctement, vous souhaitez parfois servir la version mise en cache jusqu'à ce que le fichier soit modifié. (avec la solution ci-dessus, il désactive complètement le cache pour cette image) Donc, pour servir une image en cache à partir du navigateur jusqu'à la modification, l'utilisation du fichier image a changé:

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

filemtime () obtient l'heure de modification du fichier.

Votre problème est que, malgré l'en-tête Expires:, votre navigateur réutilise sa copie en mémoire de l'image avant sa mise à jour, plutôt que de vérifier son cache.

J'ai eu une situation très similaire en téléchargeant des images de produit dans le backend d'administrateur pour un site de type magasin, et dans mon cas, j'ai décidé que la meilleure option consistait à utiliser javascript pour forcer l'actualisation d'une image, sans utiliser aucun des outils de modification d'URL. techniques d'autres personnes ont déjà mentionné ici. Au lieu de cela, j'ai placé l'URL de l'image dans un IFRAME caché, appelé location.reload(true) dans la fenêtre de l'IFRAME, puis j'ai remplacé mon image sur la page. Cela force l'actualisation de l'image, non seulement sur la page sur laquelle je suis affiché, mais également sur les pages suivantes que je visite - sans que le client ou le serveur n'ait à mémoriser les paramètres de chaîne de requête d'URL ou d'identificateur de fragment.

J'ai posté du code pour le faire dans ma réponse ici .

Ajouter un horodatage <img src="picture.jpg?t=<?php echo time();?>">

donnera toujours à votre fichier un nombre aléatoire à la fin et arrêtera sa mise en cache

Étant donné le potentiel de proxys transparents mal agencés entre vous et le client, le seul moyen de garantir totalement que les images ne seront pas mises en cache est de leur attribuer un uri unique, comme si vous avez placé un horodatage sous forme de chaîne de requête ou partie du chemin.

Si cet horodatage correspond à la dernière heure de mise à jour de l'image, vous pouvez alors le mettre en cache lorsque vous en avez besoin et servir la nouvelle image au bon moment.

Je suppose que la question initiale concerne les images stockées avec des informations textuelles. Ainsi, si vous avez accès à un contexte de texte lors de la génération de src = ... url, envisagez de stocker / utiliser CRC32 d'octets d'image au lieu d'un tampon aléatoire ou d'une marque temporelle. Ensuite, si la page contenant de nombreuses images est affichée, seules les images mises à jour seront rechargées. Si le stockage CRC est impossible, il peut être calculé et ajouté à l’URL au moment de l’exécution.

De mon point de vue, désactiver la mise en cache des images est une mauvaise idée. Du tout.

Le problème fondamental est le suivant: comment forcer le navigateur à mettre à jour une image, une fois celle-ci mise à jour côté serveur.

Encore une fois, de mon point de vue personnel, la meilleure solution consiste à désactiver l’accès direct aux images. Accédez plutôt aux images via un filtre / servlet / autre outil / service similaire côté serveur.

Dans mon cas, il s’agit d’un service de repos, qui renvoie une image et joint ETag en réponse. Le service conserve le hachage de tous les fichiers. Si le fichier est modifié, le hachage est mis à jour. Cela fonctionne parfaitement dans tous les navigateurs modernes. Oui, sa mise en œuvre prend du temps, mais cela en vaut la peine.

La seule exception: les favicons. Pour certaines raisons, cela ne fonctionne pas. Je ne pouvais pas forcer le navigateur à mettre à jour son cache du côté serveur. ETags, Cache Control, Expires, en-têtes Pragma, rien n'y fait.

Dans ce cas, il semble que l'ajout d'un paramètre random / version dans l'URL soit la seule solution.

Idéalement, vous devriez ajouter un bouton / raccourci clavier / menu à chaque page Web avec une option pour synchroniser le contenu.

Pour ce faire, gardez une trace des ressources qui doivent éventuellement être synchronisées et utilisez soit xhr pour sonder les images avec une chaîne de requête dynamique, soit créez une image au moment de l'exécution avec src à l'aide d'une chaîne de requête dynamique. Ensuite, utilisez un mécanisme de diffusion pour notifier tous composants des pages Web qui utilisent la ressource à mettre à jour pour utiliser la ressource avec une chaîne de requête dynamique ajoutée à son URL.

Un exemple naïf ressemble à ceci:

Normalement, l'image est affichée et mise en cache, mais si l'utilisateur a appuyé sur le bouton, une demande xhr est envoyée à la ressource avec une chaîne de requête temporelle qui lui est ajoutée. étant donné que le temps peut être supposé différent sur chaque presse, le navigateur évitera le cache car il ne peut pas dire si la ressource est générée dynamiquement côté serveur en fonction de la requête ou s'il s'agit d'une requête statique. ressource qui ignore la requête.

Le résultat est que vous pouvez éviter que tous vos utilisateurs ne vous bombardent de requêtes de ressources tout le temps, mais en même temps, autorisez un mécanisme permettant aux utilisateurs de mettre à jour leurs ressources s’ils soupçonnent qu’ils ne sont pas synchronisés.

<!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>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top