2012-02-08 80 views
3

在我的項目緩存文件的列表,我嘗試使用HTML5應用程序緩存到緩存靜態資源,如CSS和JS,而「用戶專用」的文件,如圖片和視頻。當我說用戶特定的圖像/視頻時,我試圖爲每個用戶分別提供文件,並且還需要控制文件下載的順序。HTML5應用程序緩存,獲取客戶端

鑑於此場景,我的清單文件將爲每個用戶動態加載。有沒有一種方法可以獲得已經在客戶端緩存的資源列表?

如果沒有,是否可以讀取客戶端的「.appcache」文件?

回答

4

是的。您可以使用AJAX請求獲取清單緩存文件,然後讀取它。

但是,這並不能保證問題中的瀏覽器具有可用的文件。

下面是一個示例代碼

  • ,檢查我們是否緩存HTML5應用或不

  • 如果我們不在緩存狀態再算上在清單中加載的資源並顯示進度根據清單緩存條目計數(總計),並對所有URL執行手動AJAX GET請求以預熱緩存。瀏覽器本身會這樣做,但通過這種方式,我們可以從流程中獲取一些進度信息。

  • 當緩存處於一個已知的良好狀態,前進

免責聲明:沒有測試工作自2010年

/** 
* HTML5 offline manifest preloader. 
* 
* Load all manifest cached entries, so that they are immediately available during the web app execution. 
* Display some nice JQuery progress while loading. 
* 
* @copyright 2010 mFabrik Research Oy 
* 
* @author Mikko Ohtamaa, http://opensourcehacker.com 
*/ 

/** 
* Preloader class constructor. 
* 
* Manifest is retrieved via HTTP GET and parsed. 
* All cache entries are loaded using HTTP GET. 
* 
* Local storage attribute "preloaded" is used to check whether loading needs to be performed, 
* as it is quite taxing operation. 
* 
* To debug this code and force retrieving of all manifest URLs, add reloaded=true HTTP GET query parameter: 
* 
* 
* 
* @param {Function} endCallback will be called when all offline entries are loaded 
* 
* @param {Object} progressMonitor ProgressMonitor object for which the status of the loading is reported. 
*/ 
function Preloader(endCallback, progressMonitor, debug) { 

    if(!progressMonitor) { 
     throw "progressMonitor must be defined"; 
    } 

    this.endCallback = endCallback; 
    this.progressMonitor = progressMonitor; 
    this.logging = debug; // Flag to control console.log() output 
} 

Preloader.prototype = { 
    /** 
    * Load HTML5 manifest and parse its data 
    * 
    * @param data: String, manifest file data 
    * @return Array of cache entries 
    * 
    * @throw: Exception if parsing fails 
    */ 
    parseManifest : function(data) { 

     /* Declare some helper string functions 
     * 
     * http://rickyrosario.com/blog/javascript-startswith-and-endswith-implementation-for-strings/ 
     * 
     */ 
     function startswith(str, prefix) { 
      return str.indexOf(prefix) === 0; 
     } 

     var entries = []; 

     var sections = ["NETWORK", "CACHE", "FALLBACK"]; 
     var currentSection = "CACHE"; 

     var lines = data.split(/\r\n|\r|\n/); 
     var i; 

     if(lines.length <= 1) { 
      throw "Manifest does not contain text lines"; 
     } 

     var firstLine = lines[0]; 
     if(!(startswith(firstLine, "CACHE MANIFEST"))) { 
      throw "Invalid cache manifest header:" + firstLine; 
     } 

     for(i=1; i<lines.length; i++) { 

      var line = lines[i]; 
      this.debug("Parsing line:" + line); 

      // If whitespace trimmed line is empty, skip it 
      line = jQuery.trim(line); 
      if(line == "") { 
       continue; 
      } 

      if(line[0] == "#") { 
       // skip comment; 
       continue; 
      } 

      // Test for a new section 
      var s = 0; 
      var sectionDetected = false; 
      for(s=0; s<sections.length; s++) { 
       var section = sections[s]; 
       if(startswith(line, section + ":")) { 
        currentSection = section; 
        sectionDetected = true; 
       } 
      } 

      if(sectionDetected) { 
       continue; 
      } 

      // Otherwise assume we can check for cached url 
      if(currentSection == "CACHE") { 
       entries.push(line); 
      } 

     } 

     return entries; 
    }, 

    /** 
    * Manifest is given as an <html> attribute. 
    */ 
    extractManifestURL : function() { 
     var url = $("html").attr("manifest"); 
     if(url === null) { 
      alert("Preloader cannot find manifest URL from <html> tag"); 
      return null; 
     } 
     return url; 
    }, 

    isPreloaded : function() { 
     // May be null or false 
     return localStorage.getItem("preloaded") == true; 
    }, 

    setPreloaded : function(status) { 
     localStorage.setItem("preloaded", status); 
    }, 

    /** 
    * Check whether we need to purge offline cache. 
    * 
    */ 
    isForcedReload : function() { 

     // http://www.netlobo.com/url_query_string_javascript.html 
     function getQueryParam(name) { 
      name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]"); 
      var regexS = "[\\?&]"+name+"=([^&#]*)"; 
      var regex = new RegExp(regexS); 
      var results = regex.exec(window.location.href); 
      if (results == null) { 
      return ""; 
      } else { 
      return results[1]; 
      } 
     } 

     if(getQueryParam("reload") == "true") { 
      return true; 
     } 

     return false; 
    }, 

    /** 
    * Do everything necessary to set-up offline application 
    */ 
    load : function() { 

     this.debug("Entering preloader"); 

     if (window.applicationCache) { 
      this.debug("ApplicationCache status " + window.applicationCache.status); 
      this.debug("Please see http://www.w3.org/TR/html5/offline.html#applicationcache"); 
     } else { 
      this.silentError("The browser does not support HTML5 applicationCache object"); 
      return; 
     } 

     var cold; 

     if(this.isPreloaded()) { 
      // We have succesfully completed preloading before 
      // ...move forward 

      forceReload = this.isForcedReload(); 
      if (forceReload == true) { 
       applicationCache.update(); 
      } else { 
       this.endCallback(); 
       return; 
      } 

      cold = false; 
     } else { 
      cold = true; 
     } 

     var url = this.extractManifestURL(); 
     if(url === null) { 
      return; 
     } 

     this.progressMonitor.startProgress(cold); 

     $.get(url, {}, jQuery.proxy(manifestLoadedCallback, this)); 

     function manifestLoadedCallback(data, textStatus, xhr) { 
      this.debug("Manifest retrieved"); 
      var text = data; 
      manifestEntries = this.parseManifest(text); 
      this.debug("Parsed manifest entries:" + manifestEntries.length); 
      this.populateCache(manifestEntries); 
     } 
    }, 


    /** 
    * Bootstrap async loading of cache entries. 
    * 
    * @param {Object} entrires 
    */ 
    populateCache : function(entries) { 
     this.manifestEntries = entries; 
     this.currentEntry = 0; 
     this.maxEntry = entries.length; 
     this.loadNextEntry(); 
    }, 

    /** 
    * Make AJAX request to next entry and update progress bar. 
    * 
    */ 
    loadNextEntry : function() { 

     if(this.currentEntry >= this.maxEntry) { 
      this.setPreloaded(true); 
      this.progressMonitor.endProgress(); 
      this.endCallback(); 
     } 

     var entryURL = this.manifestEntries[this.currentEntry]; 
     this.debug("Loading entry: " + entryURL); 

     function done() { 
      this.currentEntry++; 
      this.progressMonitor.updateProgress(this.currentEntry, this.maxEntries); 
      this.loadNextEntry(); 
     } 

     this.debug("Preloader fetching:" + entryURL + " (" + this.currentEntry + "/" + this.maxEntry + ")"); 

     $.get(entryURL, {}, jQuery.proxy(done, this)); 
    }, 

    /** 
    * Write to debug console 
    * 
    * @param {String} msg 
    */ 
    debug : function(msg) { 
     if(this.logging) { 
      console.log(msg); 
     } 
    }, 

    /** 
    * Non-end user visible error message 
    * 
    * @param {Object} msg 
    */ 
    silentError : function(msg) { 
     console.log(msg); 
    } 
}; 

function ProgressMonitor() { 

} 

ProgressMonitor.prototype = { 

    /** 
    * Start progress bar... initialize as 0/0 
    */ 
    startProgress : function(coldVirgin) { 
     $("#web-app-loading-progress-monitor").show(); 
     if(coldVirgin) { 
      $("#web-app-loading-progress-monitor .first-time").show(); 
     } 
    }, 

    endProgress : function() { 
    }, 

    updateProgress : function(currentEntry, maxEntries) { 

    } 
}; 
+0

謝謝@mikko。我有一些類似的解決方案,但並不是那麼可靠。這就是我所要做的......如果客戶端知道它已經下載的文件,那麼它可以發回服務器的名稱,服務器將在其中添加必要的(剩餘的)文件到清單文件中。 (我試圖一個一個地做,然後我可以控制下載的順序)。 – NGT 2012-02-08 14:23:17

0

我也一直在努力尋找解決方案,用於發現哪些文件正在被緩存,並且提出了以下內容。

的.htaccess包裝爲我們抓住文件,應用程序緩存的目錄。

#.htaccess 
<FilesMatch "\.(mp4|mpg|MPG|m4a|wav|WAV|jpg|JPG|bmp|BMP|png|PNG|gif|GIF)$"> 
    SetHandler autho 
</FilesMatch> 
Action autho /www/restricted_access/auth.php 

然後我auth.php文件返回文件(塊)的瀏覽器,但也同時給服務器(我用的數據庫表),與之前的聲明APPID記錄。

當檢測到「進步」事件這樣的話,一個AJAX調用可以進行檢索APPID最後一個條目,其中包含文件名和有多少數據被髮送。

使用這種方法的優點是,它的透明,以訪問在「htaccess的包裹」文件夾中的文件的其他方法,在我的情況下,也包括認證。

無論什麼原因,我無權訪問文件時,我會返回「未授權」標頭。