Domanda

Sfondo

Sto scrivendo e usando un semplicissimo strumento di gestione dei contenuti basato su CGI (Perl) per due siti Web pro-bono. Fornisce all'amministratore del sito Web moduli HTML per gli eventi in cui compilano i campi (data, luogo, titolo, descrizione, collegamenti, ecc.) E li salvano. In tale modulo consento all'amministratore di caricare un'immagine relativa all'evento. Nella pagina HTML che mostra il modulo, sto anche mostrando un'anteprima dell'immagine caricata (tag img HTML).

Il problema

Il problema si verifica quando l'amministratore desidera cambiare l'immagine. Dovrebbe solo premere il & Quot; sfogliare & Quot; pulsante, scegli una nuova foto e premi ok. E questo funziona bene.

Una volta caricata l'immagine, il mio CGI back-end gestisce il caricamento e ricarica il modulo correttamente.

Il problema è che l'immagine mostrata non viene aggiornata. La vecchia immagine è ancora mostrata, anche se il database contiene l'immagine giusta. L'ho ridotto al fatto che l'IMMAGINE È CACCIATA nel browser web. Se l'amministratore preme il pulsante RELOAD in Firefox / Explorer / Safari, tutto viene aggiornato correttamente e la nuova immagine appare appena.

La mia soluzione - non funziona

Sto cercando di controllare la cache scrivendo un'istruzione HTTP Expires con una data molto lontana nel passato.

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

Ricorda che sono dal lato amministrativo e non mi interessa davvero se le pagine impiegano un po 'più tempo a caricarsi perché sono sempre scadute.

Ma neanche questo funziona.

Note

Quando si carica un'immagine, il suo nome file non viene conservato nel database. È stato rinominato come Image.jpg (per semplificare le cose quando lo si utilizza). Quando si sostituisce l'immagine esistente con una nuova, neanche il nome cambia. Cambia solo il contenuto del file immagine.

Il server web è fornito dal servizio di hosting / ISP. Usa Apache.

Domanda

Esiste un modo per forzare il browser Web a NON memorizzare nella cache le cose da questa pagina, nemmeno le immagini?

Mi sto destreggiando con l'opzione per " salvare il nome file " con il database. In questo modo, se l'immagine viene modificata, anche l'src del tag IMG cambierà. Tuttavia, questo richiede molte modifiche in tutto il sito e preferisco non farlo se ho una soluzione migliore. Inoltre, questo non funzionerà comunque se la nuova immagine caricata ha lo stesso nome (supponiamo che l'immagine sia un po 'photoshoppata e ricaricata).

È stato utile?

Soluzione

Armin Ronacher ha l'idea corretta. Il problema è che le stringhe casuali possono scontrarsi. Vorrei usare:

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

Dove " 1222259157.415 " è l'ora corrente sul server.
Genera tempo tramite Javascript con performance.now() o Python con time.time()

Altri suggerimenti

Correzione semplice: allega una stringa di query casuale all'immagine:

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

Cosa dice HTTP RFC:

Cache-Control: no-cache

Ma non funziona così bene :)

Uso funzione temporale modificata file PHP , ad esempio:

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

Se si modifica l'immagine, viene utilizzata la nuova immagine anziché quella memorizzata nella cache, a causa di un timestamp modificato diverso.

Vorrei usare:

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

dove " 20130910043254 " è il tempo di modifica del file.

  

Quando si carica un'immagine, il suo nome file non viene conservato nel database. Viene rinominato come Image.jpg (per semplificare le cose quando lo si utilizza). Quando si sostituisce l'immagine esistente con una nuova, neanche il nome cambia. Cambia solo il contenuto del file immagine.

Penso che ci siano due tipi di soluzioni semplici: 1) quelle che vengono in mente per prime (soluzioni semplici, perché sono facili da trovare), 2) quelle con cui si finisce dopo aver riflettuto sulle cose (perché sono facili da usare). Apparentemente, non trarrai sempre beneficio se scegli di riflettere. Ma la seconda opzione è piuttosto sottovalutata, credo. Basti pensare perché php è così popolare;)

Puoi scrivere uno script proxy per pubblicare immagini, ma è un po 'più di lavoro. Qualcosa di simile a questo:

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

In realtà o intestazioni senza cache o numeri casuali su image src dovrebbero essere sufficienti, ma poiché vogliamo essere a prova di proiettile ..

Sono un NUOVO programmatore, ma ecco cosa mi è venuto in mente, per impedire al browser di memorizzare nella cache e trattenere le visualizzazioni della mia 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">

Non sono sicuro di cosa funzioni su quale browser, ma per alcuni funziona: IE: funziona quando la pagina Web viene aggiornata e quando il sito Web viene rivisitato (senza un aggiornamento). CHROME: funziona solo quando la pagina web viene aggiornata (anche dopo una rivisitazione). SAFARI e iPad: non funziona, devo cancellare l'amplificatore History &; Dati Web.

Qualche idea su SAFARI / iPad?

usa Class="NO-CACHE"

html di esempio:

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

Risultato: & Src = quot; & Images / img1.jpg quot; = > src = " images / img1.jpg? a = 0.08749723793963926 "

  

Quando si carica un'immagine, il suo nome file non viene conservato nel database. È stato rinominato come Image.jpg (per semplificare le cose quando lo si utilizza).

Cambia questo e hai risolto il tuo problema. Uso i timestamp, come per le soluzioni sopra proposte: Image-<timestamp>.jpg

Presumibilmente, tutti i problemi che stai evitando mantenendo lo stesso nome file per l'immagine possono essere superati, ma non dici quali sono.

Ho controllato tutte le risposte sul Web e la migliore sembrava essere: (in realtà non lo è)

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

all'inizio.

Tuttavia, se aggiungi il parametro cache = none (che è " none " word), non ha alcun effetto, il browser si carica comunque dalla cache.

La soluzione a questo problema era:

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

dove fondamentalmente aggiungi unix timestamp per rendere dinamico il parametro e nessuna cache, ha funzionato.

Tuttavia, il mio problema era leggermente diverso: Stavo caricando al volo l'immagine del diagramma php generato e controllando la pagina con parametri $ _GET. Volevo che l'immagine venisse letta dalla cache quando il parametro GET URL rimane lo stesso, e non memorizzare nella cache quando cambiano i parametri GET.

Per risolvere questo problema, avevo bisogno di hash $ _GET ma dato che è l'array ecco la soluzione:

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

Modifica :

Sebbene la soluzione di cui sopra funzioni bene, a volte si desidera pubblicare la versione cache FINO A quando il file viene modificato. (con la soluzione sopra, disabilita completamente la cache per quell'immagine) Quindi, per servire l'immagine memorizzata nella cache dal browser FINO A QUANDO c'è un cambiamento nell'uso del file immagine:

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

filemtime () ottiene il tempo di modifica del file.

Il tuo problema è che nonostante l'intestazione Expires:, il tuo browser sta riutilizzando la sua copia in memoria dell'immagine prima che fosse aggiornata, piuttosto che controllarne la cache.

Ho avuto una situazione molto simile durante il caricamento delle immagini dei prodotti nel back-end dell'amministratore per un sito simile a uno store e, nel mio caso, ho deciso che l'opzione migliore era utilizzare javascript per forzare un aggiornamento dell'immagine, senza utilizzare alcun URL che modifica tecniche che altre persone hanno già menzionato qui. Invece, ho inserito l'URL dell'immagine in un IFRAME nascosto, chiamato location.reload(true) nella finestra dell'IFRAME, e quindi ho sostituito la mia immagine nella pagina. Questo impone un aggiornamento dell'immagine, non solo sulla pagina in cui mi trovo, ma anche su tutte le pagine successive che visito, senza che client o server debbano ricordare alcun parametro di Querystring URL o identificatore di frammento.

Ho inserito del codice per farlo nella mia risposta qui .

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

assegnerà sempre al tuo file un numero casuale alla fine e interromperà la memorizzazione nella cache

Con il potenziale per proxy trasparenti mal comportati tra te e il cliente, l'unico modo per garantire totalmente che le immagini non vengano memorizzate nella cache è quello di dare loro un uri univoco, qualcosa come taggare un timestamp come una stringa di query o come parte del percorso.

Se quel timestamp corrisponde all'ultimo tempo di aggiornamento dell'immagine, è possibile memorizzare nella cache quando è necessario e servire la nuova immagine al momento giusto.

Presumo che la domanda originale riguardi le immagini memorizzate con alcune informazioni di testo. Pertanto, se durante la generazione dell'URL src = ... si ha accesso a un contesto testuale, prendere in considerazione l'archiviazione / utilizzo del CRC32 di byte di immagine anziché di un casuale casuale senza timestamp. Quindi, se viene visualizzata la pagina con molte immagini, verranno ricaricate solo le immagini aggiornate. Alla fine, se l'archiviazione CRC è impossibile, può essere calcolata e aggiunta all'URL in fase di esecuzione.

Dal mio punto di vista, disabilitare la memorizzazione delle immagini nella cache è una cattiva idea. Affatto.

Il problema alla radice qui è: come forzare il browser ad aggiornare l'immagine, quando è stata aggiornata sul lato server.

Ancora una volta, dal mio punto di vista personale, la soluzione migliore è disabilitare l'accesso diretto alle immagini. Accedere invece alle immagini tramite filtro / servlet lato server / altri strumenti / servizi simili.

Nel mio caso è un servizio di riposo, che restituisce immagine e allega ETag in risposta. Il servizio mantiene l'hash di tutti i file, se il file viene modificato, l'hash viene aggiornato. Funziona perfettamente con tutti i browser moderni. Sì, ci vuole tempo per implementarlo, ma ne vale la pena.

L'unica eccezione - sono le favicon. Per alcuni motivi, non funziona. Non ho potuto forzare il browser ad aggiornare la sua cache dal lato server. ETags, Cache Control, Expires, Pragma headers, nulla ha aiutato.

In questo caso, l'aggiunta di alcuni parametri random / version in url, a quanto pare, è l'unica soluzione.

Idealmente, dovresti aggiungere un pulsante / keybinding / menu a ogni pagina web con un'opzione per sincronizzare il contenuto.

Per fare ciò, dovresti tenere traccia delle risorse che potrebbero aver bisogno di essere sincronizzate e utilizzare xhr per sondare le immagini con una stringa dinamica di querys o creare un'immagine in fase di esecuzione con src usando una stringa dinamica di querystring. Quindi utilizzare un meccanismo di trasmissione per notificare tutto componenti delle pagine Web che utilizzano la risorsa per l'aggiornamento per utilizzare la risorsa con una stringa di query dinamica aggiunta al suo URL.

Un esempio ingenuo è simile al seguente:

Normalmente, l'immagine viene visualizzata e memorizzata nella cache, ma se l'utente preme il pulsante, una richiesta xhr viene inviata alla risorsa con una sequenza di query temporale aggiunta ad essa; poiché si può presumere che il tempo sia diverso a ogni pressione, si assicurerà che il browser ignori la cache in quanto non è in grado di dire se la risorsa viene generata dinamicamente sul lato server in base alla query o se si tratta di una statica risorsa che ignora la query.

Il risultato è che puoi evitare che tutti i tuoi utenti ti bombardino continuamente con richieste di risorse, ma allo stesso tempo, consentire a un meccanismo per gli utenti di aggiornare le proprie risorse se sospettano di non essere sincronizzati.

<!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>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top