2012-02-08 12 views
3

私のプロジェクトでは、HTML5のappcacheを使用してCSSやJSなどの静的リソースや画像や動画などの「ユーザー固有の」ファイルをキャッシュしようとしています。ユーザー固有の画像や動画を言うと、ユーザーごとに別々のファイルを作成しようとしており、ファイルのダウンロード順序も制御する必要があります。HTML5 appcache、クライアントにキャッシュされたファイルのリストを取得

この場合、マニフェストファイルはすべてのユーザーに動的にロードされます。すでにクライアント側にキャッシュされているリソースのリストを取得する方法はありますか?

もしそうでなければ、クライアントの ".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。私は幾分似たような解決策を持っていましたが、それはそれほど信頼できませんこれは私がやろうとしていることです...クライアントが既にダウンロードしたファイルを知っているなら、サーバはサーバに戻ることができます。サーバは必要な(残りの)ファイルをマニフェストファイルに追加します。 (私はこれを1つずつ実行しようとしていますが、次にダウンロードの順序を制御できます)。 – NGT

    0

    ので、動作するようにテストされていませんキャッシュされていて、以下を思い付いた。

    私たちがappcacheにファイルをつかんでいるディレクトリの.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と(私はDBのテーブルを使用)ブラウザに(チャンクで)ファイルを返しますが、また、サーバーに同時に記録します。

    このように 'progress'イベントが検出されている間、ファイル名と送信されたデータの量を含むAPPIDの最後のエントリを取得するためにAJAX呼び出しを行うことができます。

    この方法を使用する利点は、 '.htaccess wrapped'フォルダ内のファイルにアクセスする他のメソッドに対して透過的であり、私の場合も認証が含まれることです。

    何らかの理由でファイルにアクセスする権限が与えられていない場合は、「承認されていない」ヘッダーが返されます。

    関連する問題