オフライン Web アプリケーションの開発にはいくつかの手順が必要です:
まず、デバイスがインターネットにアクセスできるかどうかをアプリケーションが認識していることを確認します。
アプリケーションが適切に動作するには、特定のリソース (画像、JavaScript、CSS) にアクセスできる必要があります。
HTML5 で新しく定義された属性。この属性の値が true の場合はデバイスがインターネットにアクセスできることを示し、値が false の場合はデバイスがオフラインであることを示します。このプロパティの重要な点は、正しい値を返すためにブラウザがデバイスがネットワークにアクセスできるかどうかを認識する必要があるということです。
HTML5 では、オンラインとオフラインという 2 つのイベントも定義されています。
ネットワークがオフラインからオンラインに、またはオンラインからオフラインに変更されると、それぞれ 2 つのイベントがトリガーされます。
互換性
HTML5 のアプリケーション キャッシュ (略して appcache) は、オフライン Web アプリケーションの開発用に特別に設計されています。 Appcache はブラウザのキャッシュから分離されたキャッシュ領域です。
このキャッシュにデータを保存するには、マニフェスト ファイルを使用して、ダウンロードしてキャッシュするリソースをリストします。ユーザーがオフライン中に更新ボタンを押した場合でも、アプリは正常に読み込まれて実行されます。
キャッシュ インターフェイスを使用すると、アプリケーションに次の 3 つの利点がもたらされます:
オフライン ブラウジング - ユーザーはオフラインでも Web サイト全体を閲覧できます
速度 - キャッシュされたリソースはローカル リソースであるため、読み込み速度はゆっくり早く。
サーバー負荷の軽減 - ブラウザーは、変更されたサーバーからのみリソースをダウンロードします。
マニフェスト ファイルは text/cache-manifest MIME タイプとして提供する必要があります
マニフェスト ファイル形式
CACHE MANIFEST# 2010-06-18:v2# Explicitly cached 'master entries'.CACHE:/favicon.icoindex.htmlstylesheet.cssimages/logo.pngscripts/main.js# Resources that require the user to be online.NETWORK:login.php/myapihttp://api.twitter.com# static.html will be served if main.py is inaccessible# offline.jpg will be served in place of all images in images/large/# offline.html will be served in place of all other .html filesFALLBACK:/main.py /static.htmlimages/large/ images/offline.jpg*.html /offline.html
マニフェストには、CACHE、NETWORK、FALLBACK の 3 つの異なる部分を含めることができます。
キャッシュ: これはエントリのデフォルトの部分です。このヘッダーの下にリストされているファイル (または CACHE MANIFEST の直後のファイル) は、初めてダウンロードされるときに明示的にキャッシュされます。
ネットワーク: このセクションにリストされているファイルは、サーバーに接続する必要があるホワイトリストに登録されたリソースです。これらのリソースに対するすべてのリクエストは、ユーザーがオフラインであるかどうかに関係なく、キャッシュをバイパスします。ワイルドカードを使用できます。
FALLBACK: このセクションはオプションであり、リソースにアクセスできない場合にフォールバック Web ページを指定するために使用されます。最初の URI はリソースを表し、2 番目の URI はフォールバック Web ページを表します。両方の URI は関連している必要があり、マニフェスト ファイルと同じオリジンを持つ必要があります。ワイルドカードを使用できます。
注 セクションは任意の順序で配置でき、各セクションを同じリスト内で繰り返すことができます。
マニフェスト ファイルを参照してください
<html manifest="example.appcache"> ...</html>
CACHE MANIFEST 文字列は最初の行にある必要があり、必須です。
ウェブサイトのキャッシュデータサイズは5MBを超えてはなりません。
SSL 経由で提供されるページに設定されている HTTP キャッシュ ヘッダーとキャッシュ制限は、キャッシュ マニフェストに置き換えられます (つまり、https URL は暗号化されています)。したがって、https 経由で提供される Web ページはオフラインで実行できます。
Chrome ウェブストア用のアプリを作成している場合は、unlimitedStorage を使用してこの制限を解除できます。
マニフェスト ファイルまたはその中で指定されたリソースをダウンロードできない場合、キャッシュ更新プロセス全体を続行できません。この場合、ブラウザは元のアプリケーション キャッシュを引き続き使用します。
applicationCache オブジェクトには status 属性があり、その属性の値は定数であり、アプリケーション キャッシュのステータスを示します。
0: キャッシュなし、つまりページに関連するアプリケーション キャッシュがありません
1: アイドル、つまりアプリケーション キャッシュが更新されていません
2 : チェック中、つまり、説明がファイルをダウンロードされ、更新を確認しています
3: ダウンロード中、つまり、アプリケーション キャッシュが説明ファイルで指定されたリソースをダウンロードしています
4: 更新が完了しました、つまり、アプリケーション キャッシュがリソースを更新し、すべてのリソースがダウンロードされました。 OK swapCache() を通じて使用されます
5: 放棄されました。つまり、アプリケーション キャッシュの記述ファイルが存在しなくなったため、ページを削除できなくなりました。アプリケーションキャッシュにアクセスします
チェック: ブラウザ内 アプリキャッシュがアップデートを探しているときにトリガーされます
エラー: アップデートのチェック中またはリソースのダウンロード中にエラーが発生したときにトリガーされます
noupdate:在检查描述文件无变化时粗放
downloading:在开始下载应用缓存时资源时触发
progress:在文件下载应用缓存资源时粗放
updateready:在页面新的应用缓存下载完毕,而且可以通过swapCache()时触发。
兼容性
HTTP cookie,通常叫做cookie,最初是在客户端用于存储会话信息的。该标准要求服务器的任意HTTP请求发送Set-Cookie HTTP头部作为响应的一部分,其中包含会话信息。
// HTTP响应HTTP/1.1 200 OKContent-type: text/htmlSet-cookie: name=valueOther-header: other-header-value // HTTP请求GET /index.html HTTP/1.1Cookie: name=valueOther-header: other-header-value
第一段会话过程
服务器:设置name=value的cookie,并将其作为响应头部的一部分,发送给浏览器。
浏览器:储存name=value的cookie并将其作为请求头的一部分,发送给服务器。
会话过程的名称和值都是经过URL编码的。
每个域的cookie总数是有限的,不同浏览器之间各有不同。当超过单个域名限制之后还有再设置cookie,浏览器就会清除以前的cookie。
cookie在性质上是绑定在特定域名下的。当设定一个cookie后,再给创建它的域名发送请求时,都会包含这个cookie。
// HTTP响应HTTP/1.1 200 OKContent-type: text/htmlSet-cookie: name=value; expires=Mon, 22-JAN-07 07:10:24 GMT; domain=.wrox.com;path=/;secureOther-header: other-header-value // HTTP请求GET /index.html HTTP/1.1Cookie: name=valueOther-header: other-header-value
名称(name):一个唯一确定cookie的名称,cookie的名称必须是经过 URL编码的。
值(value):储存在cookie的字符串值,值必须被 URL编码。
域:cookie对于那个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。如果没有明确设定,那么这个域会被认作来自设置cookie的那个域。
路径:对于指定域中的那个路径,应该向服务器发送cookie
失效时间:表示cookie应该被删除的那个时间戳
安全标志:指定后,cookie只能在SSL的连接时,才能发送到服务器
第二段会话过程
服务器:设置name=value的cookie,同时告诉浏览器
它会在格林威治时间2007年1月22日7:20:24失效。
对于所有wrox.com的子域和域名下(由path参数指定的)都有效
同时通过SSL连接才能传输。并将其作为响应头部的一部分,发送给浏览器。
浏览器:储存name=value的cookie并将其作为请求头的一部分,发送给服务器。
Note:后四个,域/路径/失效时间/安全标志都是 服务器给浏览器的指示。以指定何时该发送cookie。这些参数并不会作为发送到服务器的标志,名值对才会被发送。只有cookie的名字和值是必须的。
读
用来获取属性值时, document.cookie返回当前页面可用的(根据cookie的域,路径,失效时间和安全设置)所有的cookie的字符串。
[]()
写
当用来设置值得时候, document.cookie可以用来设置新的cookie字符串。这个cookie字符串会用来解释并添加到现有的cookie中。设置的值并不会覆盖cookie,除非设置的值已经存在。
var cookieUtil = { get: function ( name ) { var cookieName = encodeURIComponent( name ) + '=', cookieStart = document.cookie.indexOf(cookieName), cookieValue = null; if( cookieStart > -1 ) { var cookieEnd = document.cookie.indexOf(';',cookieStart); if( cookieEnd === -1 ) { cookieEnd = document.length; } cookieValue = decodeURIComponent( document.cookie ).substring(cookieStart+cookieName.length, cookieEnd) } return cookieValue; }, set: function ( name, value, expires, path, domain, secure ) { var cookieText = encodeURIComponent(name) + '=' + encodeURIComponent(value); if( expires instanceof Date ) { cookieText += "; expires=" + expires.toGMTString(); } if( path ) { cookieText += '; path=' + path; } if( domain ) { cookieText += '; domain=' + domain; } if( secure ) { cookieText += '; secure'; } document.cookie = cookieText; }, unset: function ( name, path, domain, secure ) { this.set( name, '' , new Date(0), path, domain, secure) }}
为了绕开 浏览器的单域名下的cookie数限制,一种开发人员使用了一种称为子cookie(subcookie)的概念。子cookie是存放在单个cookie中的更小段的数据。也就是使用cookie值来储存多个名称值对儿。
子cookie一般以查询字符串的格式进行格式化。然后这些值可以使用单个cookie进行储存和访问
name=name1=value1&name2=value2&name3=value3上面展示了如何写入,读取和删除cookie,下面展示操作子cookie的方法。
var SubCookieUtil = { get: function ( name, subName ) { var cookieValue = this.getAll( name ); if( subName ) { return result[subName]; } else { return null; } }, getAll: function ( name ) { var cookieName = encodeURIComponent( name ) + '=', cookieStart = document.cookie.indexOf( cookieName ), cookieValue = null, cookieEnd, result = {}; if( cookieStart > -1 ) { cookieEnd = document.cookie.indexOf( ';', cookieStart ); if( cookieEnd === -1 ) { cookieEnd = document.cookie.length; } } cookieValue = document.cookie.substring( cookieStart+cookieName.length, cookieEnd ); decodeURIComponent( cookieValue ); if( cookieValue.length > 0 ) { subCookies = cookieValue.split( '&' ); for( var i = 0; i < subCookies.length; i++ ) { var parts = subCookies[i].split( '=' ); result[parts[0]] = parts[1]; } return result; } else { return null; } }, set: function ( name, subName, value, expires, path, domain, secure ) { var subCookies = this.getAll( name ) || {}; subCookies[subName] = value; this.setAll( name, subCookies, expires, path, domain, secure ); }, setAll: function ( name, subCookies, expires, path, domain, secure ) { var cookieText = encodeURIComponent( name ) + '=', subCookiesParts = [], subName; for( subName in subCookies ) { if( subCookies.hasOwnProperty( subName ) ) { subCookiesParts.push( encodeURIComponent(subName) + '=' + encodeURIComponent(subCookies[subName]) ); } } if( subCookiesParts.length > 0 ) { cookieText += subCookiesParts.join('&'); if( expires instanceof Date ) { cookieText += '; expires=' + expires.toGMTString(); } if( path ) { cookieText += '; path=' + path; } if( domain ) { cookieText += '; domain=' + domain; } if( secure ) { cookieText += '; secure' } } else { cookieText += '; expires=' + (new Date(0).toGMTString()); } document.cookie = cookieText; }, unsetAll: function ( name, subCookies, expires, path, domain, secure ) { this.set( name, null, new Date(0), path, domain, secure ); }, unset: function ( name, subName, expires, path, domain, secure ) { var subCookies = this.get( name ); if( subCookies ) { delete subCookies[subName] this.setAll( name, subCookies, expires, path, domain, secure ); } }}
由于所有的cookie都会由浏览器作为请求头发送,所以在cookie中存储大量信息会影响到特定域的请求性能。cookie信息越大,完成对服务器请求的时间也就越长。
cookie数据并非存储在一个安全环境中,其中包含的任何数据都可被他人访问。所以一定不要在cookie中储存重要和敏感的数据。
在IE5.0中,微软通过一个自定义行为引入了持久化用户数据的概念。用户数据允许每个文档最多128KB数据,每个域名最多1MB数据。要使用持久化用户数据,首先,必须如下所示,使用CSS在某个元素上指定userData行为。
`<div style="behavior:url(#default#userData)" id="dataStore"></div>`
var dataStore = getElementById('dataStore');// 写入数据dataStore.setAttribute('name','Nicholas');dataStore.setAttribute('book','Professional Javascript');dataStore.save('BookInfo');// 获取数据dataStore.load('BookInfo'); // 访问数据console.log(dataStore.getAttribute('name'));console.log(dataStor.getAttribute('book'));// 删除数据dataStore.removeAttribute( 'name' );dataStore.removeAttribute( 'book' );dataStore.save('BookInfo');
和cookie一样,IE用户数据并非安全的,所有不能存放敏感信息。
用户数据默认是可以跨越会话持久存在的,同时也不会过期
要访问某个数据空间,脚本运行的页面必须来自于同一个域名,路径并使用与进行存储的脚本同样的协议。
Web Storage的两个主要目标是
提供一种在cookie之外存储会话数据的途径
提供一种存储大量可以跨会话存在的数据的机制。
兼容性
Note:与其他客户端储存方案相比,WebStorage同样也有限制,这些限制因浏览器围而异。一般来说,对存储空间大小的限制都是以每个来源(协议,域名,端口号)为单位的。换句话说,每个来源都要固定大小的空间用于保存自己的数据。考虑到这个限制,就要注意分析和控制每个来源中有多少页面需要保存数据。
webStorage限制测试
Storage提供最大的空间(因浏览器而异)来储存名值对。
sessionStorage instanceof Storage // truelocalStorage instanceof Storage// truelocalStorage.__proto__ === Storage.prototype // truesessionStorage.__proto__ === Storage.prototype // true
由上可知, sessionStorage对象与 localStorage对象都为Storge类型的实例。因此它们都可以访问到Storage类型的原型对象上的方法。有如下这些方法。
clear():删除所有值;Firefox中没有实现
getItem(name):根据指定的名字name获取对应的值
key(index):获得index位置处的值得名字
removeItem(name):删除由name指定的名值对
setItem(nname, value):为指定的name设置一个对应的值
同时可以使用length属性判断Storage对象中有多少名值对。但无法判断对象中所有数据的大小,不过IE8提供了一个 remainingSpace属性,用于获取还可以使用的存储空间的字节数。
Note:Storge类型只能存储字符串。非字符串的数据在存储之前会被转换为字符串。
为每一个给定的源(given origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复)。
sessionStorage对象主要用于仅针对会话的小段数据的存储。它储存特定于某个会话的数据,也就是该数据只保持到浏览器关闭。这个对象就像会话cookie,也会在浏览器关闭后消失。
存储在sessionStorage中的数据可以跨越页面而存在,同时如果浏览器支持,浏览器崩溃重启后依然可用(Firefox和Webkit都支持,IE不行)。
sessionStorage对象绑定于某个服务器会话,所有当文件在本地运行的时候是不可用的。
存储在sessionStorage的数据只能由最初给对象储存数据的的页面访问到,所以对多页面应用有限制。
// 写入数据sessionStorage.setItem( 'name', 'Nicholas' );// 访问数据sessionStorage.getItem( 'name' );// 迭代数据for( var i = 0,len = sessionStorage.length; i < len; i++ ) { var key = sessionStorge.key( i ); var value = sessionStorage.getItem( key ); console.log( key + '=' + value );}for(key in sessionStorage) { var value = sessionStorage.getItem( key ); console.log( key + '=' + value );}// 删除数据sessionStorage.removeItem( 'name' );
Note:不同浏览器写入数据的方法略有不同。Firefox和Webkit实现了同步写入,所有添加到储存空间的数据是立刻被提交的。而IE的实现是异步写入数据,所以在设置数据和将数据写入磁盘之间可能有一些延迟。对于少量数据而言,这个差异是可以忽略的。对于大量数据,你会发现IE比其他浏览器更快的恢复执行,因为它会跳过实际的磁盘写入过程。
在IE8中可强制把数据写入磁盘,如下。
// 防止代码执行的时候,不会发生其他磁盘写入操作sessionStorage.begin();sessionStorage.name = 'Nicholas';// 确保name的值在调用commit()之后立刻写入磁盘sessionStorage.commit();
localStorage 同样的功能,但是在浏览器关闭,然后重新打开后数据仍然存在。
localStorage はセッション全体にデータ ストレージを実装し、クライアント データを永続化するためのソリューションとして HTML5 仕様の globalStorage を置き換えます。ルール: 同じ localStorage オブジェクトにアクセスするには、ページが同じドメイン名から取得され (サブドメイン名は無効です)、同じプロトコルを使用し、同じポート上に存在する必要があります。
localStorage は Storage のインスタンスであるため、sessionStorage と同じように使用できます。
Storage オブジェクトに変更を加えると、ドキュメント上でストレージ イベントがトリガーされます。
domain: 変更されたストレージスペースのドメイン名
key: 設定または削除されたキー名
newValue: 値が設定されている場合、それは新しい値です。削除されたキーの場合は null です
oldValue: キーが変更される前の値