代码之家  ›  专栏  ›  技术社区  ›  Justin Searls

如何正确地使联机/脱机Web应用程序的HTML5缓存清单无效?

  •  53
  • Justin Searls  · 技术社区  · 15 年前

    我目前正在使用缓存清单(如前所述 here )这有效地使运行应用程序所需的资源在用户脱机时可用。

    不幸的是,它工作得有点太好了。

    加载缓存清单后,firefox 3.5+缓存缓存清单中显式引用的所有资源。但是,如果服务器上的文件被更新,并且用户试图在联机时强制刷新页面(包括缓存清单本身),那么火狐将绝对拒绝获取任何内容。应用程序在最后一次缓存时保持完全冻结状态。问题:

    1. 我希望火狐在网络连接失败时只有效地依赖缓存的资源。我试过使用回退块,但没有用。这是可能的吗?
    2. 如果1不可能,用户是否可以强制刷新页面并绕过此缓存(ctrl-f5不可能,而且清除浏览器缓存也不可能,令人震惊)而不清除其私有数据?另外,缓存清单机制是否支持过期头文件,以及它与此相关的行为是否记录在任何地方?
    6 回复  |  直到 10 年前
        1
  •  25
  •   Justin Searls    15 年前

    我想我已经弄明白了:如果缓存清单中有错误(比如,引用的文件不存在),那么火狐将完全停止处理任何与applicationcache相关的内容。也就是说,它不会更新缓存中的任何内容,包括缓存的缓存清单。

    为了发现这是问题所在,我 borrowed some code from Mozilla 并将其放到我的应用程序中的一个新(非缓存)HTML文件中。记录的最后一条消息指出,我的缓存清单中可能有问题,而且确实有足够的问题(一个丢失的文件)。

    
    // 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 }

    这当然有帮助,但我绝对应该向Mozilla请求一个功能,至少可以将格式错误的缓存清单打印到错误控制台。它不应该要求自定义代码附加到这些事件来诊断与重命名文件一样微不足道的问题。

        2
  •  15
  •   Cjxcz Odjcayrwl    13 年前

    我使用的代码来自 HTML5 Rocks: Update the 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);
    
        3
  •  7
  •   GeoNomad    15 年前

    免责声明:我对清单和缓存的经验是所有的Safari和FF可能会处理一些不同的事情。

    1. 你说得很对。如果清单上列出的任何文件找不到,则不会发生缓存。

    2. 即使联机,浏览器也只检查清单文件。在等待清单文件时,它将继续从缓存中加载站点-这样不会延迟渲染-但这意味着您在第一次加载时看不到任何更改。

    3. 下次加载站点时,如果清单在上一次加载时发生更改,则将加载新文件。

    总是需要重新加载两次才能看到任何更改。实际上,我有时需要重新加载3次才能看到更新。不知道为什么。

    调试时,我会使用PHP动态生成清单文件,因此文件名中不可能出现拼写错误。我也会每次随机生成版本号来强制更新,但仍然有一个离线的webapp用于测试。

    一旦完成,PHP文件就可以用一个恒定的版本号来回送保存的清单数据,并且始终使用缓存。

    只是我最近玩清单和缓存时学到的一些东西。它工作得很好,但可能会令人困惑。

    没有过期。要取消缓存,必须将清单文件更改为不包含任何内容,然后重新加载。在Safari上,清除用户缓存会清除所有缓存的文件。

        4
  •  7
  •   OlliM Bless Yahu    10 年前

    我也有同样的问题:一旦火狐保存了离线文件,它就永远不会重新加载这些文件。Chrome按预期工作,它检查清单文件是否有更改,如果清单文件发生更改,则重新加载所有内容。火狐甚至没有从服务器下载清单文件,所以它没有注意到更改。

    经过调查,我发现火狐正在缓存缓存清单文件(老式缓存,而不是离线缓存)。将清单文件的缓存头设置为 Cache-Control: no-cache, private 解决了问题。

        5
  •  3
  •   keigoi    14 年前

    我做了一个火狐插件,它使缓存清单失效,并清除HTML5本地存储。

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

    还可以通过在错误控制台中键入以下代码使缓存清单无效:

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

    或者,通过在地址栏中键入以下代码,可以手动强制更新缓存:

    javascript:applicationCache.update()
    
        6
  •  2
  •   BobFromBris    14 年前

    嗯,我刚刚在缓存中调用了update(),在对清单文件进行编辑更改之后,收到了检查/下载/就绪的完整序列,进行了一次重新加载,并在我的一个JS文件中进行了一次文本更改,该更改显示在我的应用程序的初始页面中,很快就出现了。

    看来我只需要一个重装。

    推荐文章