web-dev-qa-db-fra.com

Comment invalider correctement un manifeste de cache HTML5 pour les applications Web en ligne / hors ligne?

J'utilise actuellement un manifeste de cache (comme décrit ici ). Cela rend effectivement les ressources nécessaires pour exécuter l'application disponibles lorsque l'utilisateur est hors ligne.

Malheureusement, cela fonctionne un peu trop bien.

Une fois le manifeste de cache chargé, Firefox 3.5+ met en cache toutes les ressources référencées explicitement dans le manifeste de cache. Cependant, si un fichier sur le serveur est mis à jour et que l'utilisateur essaie d'actualiser de force la page en ligne (y compris le manifeste de cache lui-même), Firefox refusera absolument de récupérer quoi que ce soit. L'application reste complètement gelée au dernier point où elle a été mise en cache. Des questions:

  1. Je veux que Firefox ne s'appuie efficacement sur les ressources mises en cache que lorsque la connexion réseau échoue. J'ai essayé d'utiliser le bloc FALLBACK, mais en vain. Est-ce seulement possible?
  2. Si # 1 n'est pas possible, est-il possible pour l'utilisateur de forcer l'actualisation d'une page et de contourner ce cache (ctrl-F5 ne le fait pas et l'effacement du cache du navigateur, de manière choquante) à court d'effacement de leurs données privées? Alternativement, le mécanisme de cache-manifeste prend-il en charge les en-têtes d'expiration et son comportement à cet égard est-il documenté quelque part?
53
Justin Searls

Je pense que j'ai compris: s'il y a une erreur dans le cache-manifeste (par exemple, un fichier référencé n'existe pas), Firefox arrêtera complètement de traiter tout ce qui est lié à ApplicationCache. Cela signifie qu'il ne mettra à jour rien dans votre cache, y compris votre manifeste de cache mis en cache.

Pour découvrir que c'était le problème, j'ai emprunté du code à Mozilla et l'ai déposé dans un nouveau fichier HTML (non mis en cache) dans mon application. Le dernier message enregistré indiquait qu'il pouvait y avoir un problème dans mon cache-manifeste, et bien sûr il y en avait (un fichier manquant).


// Convenience array of status values
var cacheStatusValues = [];
 cacheStatusValues[0] = 'uncached';
 cacheStatusValues[1] = 'idle';
 cacheStatusValues[2] = 'checking';
 cacheStatusValues[3] = 'downloading';
 cacheStatusValues[4] = 'updateready';
 cacheStatusValues[5] = 'obsolete';

 // Listeners for all possible events
 var cache = window.applicationCache;
 cache.addEventListener('cached', logEvent, false);
 cache.addEventListener('checking', logEvent, false);
 cache.addEventListener('downloading', logEvent, false);
 cache.addEventListener('error', logEvent, false);
 cache.addEventListener('noupdate', logEvent, false);
 cache.addEventListener('obsolete', logEvent, false);
 cache.addEventListener('progress', logEvent, false);
 cache.addEventListener('updateready', logEvent, false);

 // Log every event to the console
 function logEvent(e) {
     var online, status, type, message;
     online = (isOnline()) ? 'yes' : 'no';
     status = cacheStatusValues[cache.status];
     type = e.type;
     message = 'online: ' + online;
     message+= ', event: ' + type;
     message+= ', status: ' + status;
     if (type == 'error' && navigator.onLine) {
         message+= ' There was an unknown error, check your Cache Manifest.';
     }
     log('
'+message); } function log(s) { alert(s); } function isOnline() { return navigator.onLine; } if (!$('html').attr('manifest')) { log('No Cache Manifest listed on the tag.') } // Swap in newly download files when update is ready cache.addEventListener('updateready', function(e){ // Don't perform "swap" if this is the first cache if (cacheStatusValues[cache.status] != 'idle') { cache.swapCache(); log('Swapped/updated the Cache Manifest.'); } } , false); // These two functions check for updates to the manifest file function checkForUpdates(){ cache.update(); } function autoCheckForUpdates(){ setInterval(function(){cache.update()}, 10000); } return { isOnline: isOnline, checkForUpdates: checkForUpdates, autoCheckForUpdates: autoCheckForUpdates }

C'était certainement utile, mais je devrais certainement demander une fonctionnalité à Mozilla qui imprime des manifest-cache malformés au moins dans la console d'erreur. Il ne devrait pas nécessiter de code personnalisé à attacher à ces événements pour diagnostiquer un problème aussi trivial qu'un fichier renommé.

25
Justin Searls

J'ai utilisé du code de HTML5 Rocks: Mettre à jour le cache :

window.addEventListener('load', function(e) {
  if (window.applicationCache) {
    window.applicationCache.addEventListener('updateready', function(e) {
        if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
          // Browser downloaded a new app cache.
          // Swap it in and reload the page to get the new hotness.
          window.applicationCache.swapCache();
          if (confirm('A new version of this site is available. Load it?')) {
            window.location.reload();
          }
        } else {
          // Manifest didn't changed. Nothing new to server.
        }
    }, false);
  }
}, false);
15
Danubian Sailor

J'ai eu le même problème: une fois que Firefox a enregistré les fichiers hors ligne, il ne les rechargerait plus jamais. Chrome a fonctionné comme prévu, il a vérifié les modifications du fichier manifeste et a tout rechargé si le fichier manifeste changeait. Firefox n'a même pas téléchargé le fichier manifeste depuis le serveur, il n'a donc pas pu remarquer de changements.

Après enquête, j'ai découvert que Firefox mettait en cache le fichier manifeste de cache (cache à l'ancienne, pas le cache hors ligne). Définition de l'en-tête de cache du fichier manifeste sur Cache-Control: no-cache, private résolu le problème.

7
OlliM

Avertissement: mon expérience avec les manifestes et le cache est entièrement basée sur Safari et FF peut gérer certaines choses différemment.

  1. Vous avez parfaitement raison. S'il y a des fichiers répertoriés sur le manifeste qui ne peuvent pas être trouvés, aucune mise en cache ne se produira.

  2. Même si vous êtes en ligne, le navigateur vérifie uniquement le fichier manifeste. En attendant le fichier manifeste, il continuera à charger le site à partir du cache - de cette façon, il ne retarde pas le rendu - mais cela signifie que vous ne voyez aucun changement lors du premier chargement.

  3. La prochaine fois que le site sera chargé, si le manifeste a changé lors du chargement précédent, les nouveaux fichiers seront chargés.

IL IS TOUJOURS NÉCESSAIRE POUR RECHARGER DEUX FOIS pour voir les changements. En fait, j'ai parfois dû recharger 3 fois pour voir la mise à jour. Aucune idée pourquoi.

Lors du débogage, je génère mon fichier manifeste à la volée avec php, il n'y a donc aucune chance de faute de frappe dans un nom de fichier. Je génère également le numéro de version au hasard à chaque fois pour forcer une mise à jour, mais j'ai toujours une webapp hors ligne pour les tests.

Une fois terminé, le fichier php peut simplement faire écho aux données manifestes enregistrées avec un numéro de version constant et le cache sera toujours utilisé.

Juste quelques choses que j'ai apprises en jouant avec le manifeste et le cache récemment. Cela fonctionne très bien, mais peut être déroutant.

Il n'y a pas d'expiration. Pour annuler la mise en cache, vous devez modifier le fichier manifeste pour ne rien y faire et effectuer un rechargement. Sur Safari, l'effacement du cache utilisateur efface tous les fichiers mis en cache.

7
GeoNomad

J'ai créé un module complémentaire Firefox qui invalide le manifeste de cache et efface le stockage local HTML5.

http://sites.google.com/site/keigoattic/home/webrelated#TOC-Firefox-HTML5-Offline-Cache-and-Loc

Vous pouvez également invalider le manifeste de cache en tapant le code ci-dessous dans la console d'erreur:

// invalidates the cache manifest
var mani = "http://.../mysite.manifest"; // manifest URL
Components.classes["@mozilla.org/network/application-cache-service;1"].getService(Components.interfaces.nsIApplicationCacheService).getActiveCache(mani).discard();

Ou, en tapant le code ci-dessous dans la barre d'adresse, vous appliquerez manuellement le cache à mettre à jour:

javascript:applicationCache.update()
3
keigoi

Hmm, je viens d'appeler update () sur le cache, après avoir apporté une modification d'édition au fichier manifeste, et reçu la séquence complète de vérification/téléchargement/prêt, j'ai fait un rechargement et un changement de texte que j'avais fait dans l'un de mes js les fichiers, qui apparaissent dans la page initiale de mon application, sont rapidement apparus.

Semble que je n'ai besoin que d'une recharge.

2
BobFromBris