绝大多数的软件都需要使用某种具有持久性的方式来存储数据,Web Apps 也不例外,涉及到完整后台的 Web Apps ,可以直接在后台使用 mysql 等数据库来存储数据,但过多的 sql 查询会影响服务器性能,甚至是整个 App 的性能。因此,一些简单有效的存储方式对与 Web Apps 显得很重要,Web Storage 似乎正是为此而设计。下面开始正式介绍 Web Storage 。
一. Web Storage 是什么?
Web Storage 是 HTML5 中用于在客户端存储数据的方法,有两种形式:localStorage(本地存储)和 sessionStorage(会话存储)。这两种方法都允许使用 JavaScript 设置“键值对”,并保存在客户端中,在重新加载页面时读出它们。熟悉 Web 开发的读者会发现,这与 cookie 的机制很相似,但与 cookie 相比,它们有很大的差异:
cookie
cookie 不适合大量数据的存储,因为它们由每个对服务器的请求来传递,这使得 cookie 速度很慢而且效率也不高。
Web Storage
Web Storage 的数据完全存储在客户端,不需要通过浏览器的请求再传输到服务器,这样不但可以存储更多的数据,速度也较快。并且,Web Storage 具有统一的编程接口,使得数据操作更为简便。
二. localStorage(本地存储)和 sessionStorage(会话存储)
上面有提及,Web Storage 有 localStorage 和 sessionStorage 两种形式,它们在功能上是一样的,只是持久性和范围有所不同,具体如下:
1. localStorage
localStorage 方式存储的数据没有时间限制,即使浏览窗口关闭了,数据也会保存下来,这些数据也可用于所有来自同源(即域名,协议和端口均要相同)窗口(或者标签页)的加载,实际开发中用于 Web Apps 的选项设置或用户偏好设置会很有用。
2. sessionStorage
sessionStorage 方式存储的数据实际上存储在窗口对象中,当关闭浏览器窗口后,数据会被删除。由于这些数据是存储于窗口对象中,所以它们对于其他窗口或标签页不可见。实际开发中可以用于记录暂时的状态或排序。
三. 浏览器支持
关于浏览器对 Web Storage 的支持情况需要分开 API 和事件两个方面进行说明
1. API 支持情况
IE8+ ,Chrome 4+ , Firefox 3.5+ , Safari 4+ 和 Opera 10.5+ 对于 Web Storage API 有良好及基本统一的支持,
2. 事件支持情况
相对于 API ,Storage 的事件比较晚才有良好的浏览器支持,具体如下:Firefox 5+ , Safari 5+ , Chrome 12+ , Opera 10.5 + 和 IE9+
四. 使用 Web Storage API
下面会例举一些例子说明如何设置、访问和删除 Web Storage 。例子中会统一使用 localStorage ,但实际上在这些例子中使用 localStorage 或 sessionStorage 并没有区别,不过读者需要注意 sessionStorage 在关闭窗口或标签页后会丢失。
但在之前 Kayo 需要说明一点,对于不同的域(包括子域),Web Storage 的数据存储于不同的区域,并且一个网站只能访问其自身的数据。这也是 localStorage 只能访问同源窗口或标签页的原因。
1. 设置
localStorage.setItem('username', 'Kayo'); // 设置 username 为 Kayo
2. 访问
var username = localStorage.getItem('Kayo'); // 访问 username 并把其键值存储在一个变量 username 中
3. 删除
localStorage.removeItem('username'); // 删除 username 键
以上是标准的 Web Storage 基本操作,实际上还有另外一系列更实用的操作方式,假如开发者的键是有效的 JavaScript token (即没有空格、没有除下划线之外的标点),那么可以使用如下的操作方式:
localStorage.username = 'Kayo'; // 设置 username 为 Kayo var username = localStorage.username; // 访问 username 并把其键值存储在一个变量 username 中 delete localStorage.username; // 删除 username 键
由于 Web Storage 的操作基于 JavaScript ,因此 Kayo 建议使用第二种操作方式,这样会更加方便并且利于整段 JavaScript 代码的阅读。
除了上面三种基本操作外,Web Storage 还包括一个 length 属性以及以下两个方法:
4. clear()
清空一个域下的全部键值。
5. key(n)
返回一个域下 localStorage 列表或 sessionStorage 列表的第 n 个键的键名。
6. length
返回一个域下 localStorage 列表或 sessionStorage 列表的键的总数。
五. 实例
在说明了 Web Storage 的基本使用后,下面举例说明 Web Storage 的具体使用。Web Storage 虽然相对 cookie 可以存储更大的数据量,但这里的更大只是数据的大小,由于 Web Storage 采用的是“键值对”的存储方式,即一个“键名”对应一个值,这样并不利于处理大量的数据,因此 Web Storage 更适合存储辅助性的数据,尤其是处理大量相同性质的数据时,Web Storage 便显得很不灵活。在例子中,Kayo 会以大家比较熟悉的保存用户留言信息进行说明,即使用 Web Storage 代替大家熟悉的 cookie 记录用户留言信息。
例子中会有一个表单,填入表单的内容并提交,但这里会阻止默认的表单提交动作,改以存储在 localStorage ,为了方便操作,会把设置、访问键值写成独立的函数,具体的情况可以测试完整 Demo (为了简化例子结构,这里只使用 addEventListener 监听事件,请使用 Chrome, Firefox 等现代浏览器浏览 Demo ,下同)。测试方法:填写相关信息,提交表单,刷新页面,观察用户信息部分是否得到保留,为了更容易理解 Web Storage 的使用,例子中并没有制作相应的后台,并且由于阻止了表单提交,提交表单不会出现反馈,因此提交表单后直接刷新页面即可。
下面列出例子中主要的代码。
主要 HTML 结构
<form action="" id="add-comment" name="add-comment" /> <h1>发表评论</h1> <div id="userinfo"> <div class="item"> <span>用户名: </span> <input type="text" name="username" id="username" /> </div> <div class="item"> <span>E-mail: </span> <input type="email" name="email" id="email" /> </div> <div class="item"> <span>网址: </span> <input type="text" name="website" id="website" /> </div> </div> <div class="item"> <span>评论: </span> <textarea name="comment" id="comment" cols="33" rows="8"></textarea> </div> <div id="submit-info"> <input type="submit" value="发表"> </div> </form>
JavaScript 代码
var username = document.getElementById('username'), email = document.getElementById('email'), website = document.getElementById('website'), submit = document.getElementById('submit'); // 加载已保存的 localStorage function loadUserInfo(){ username.value = localStorage.username; email.value = localStorage.email; website.value = localStorage.website; } // 存储表单数据为 localStorage function saveUserInfo(){ localStorage.username = username.value; localStorage.email = email.value; localStorage.website = website.value; } // 打开页面时加载数据 loadUserInfo(); // 使用存储表单数据为 localStorage 代替表单提交 submit.addEventListener('click', function(e){ e.preventDefault(); saveUserInfo(); });
从代码量上看,由于例子比较简单,因此这并不会比 cookie 版的代码量少,但结构却简洁很多,并且操作方式很简单,即使增加更多的信息项也很方便。
除此之外,在本系列文章的第一篇中,Kayo 介绍了一个使用 jQuery Mobile 和 HTML5 开发的作品,其中“设置”的功能也是利用 Web Storage 制作,详情可以浏览第一篇文章的第六部分“作品”。
六. Web Storage 事件
Web Storage 支持一个 "storage" 事件,Web Storage 中的数据被保存后,修改或删除,都会触发 storage 事件。但由于浏览器对于该事件的支持并不完善,因此实际上在大多浏览器中,"storage" 并没有完全按照上面所说的触发。在介绍 "storage" 事件的实际效果时,Kayo 先介绍一下该事件的具体情况。
"storage" 事件会把一系列的属性封装在相应的 event 对象中,用于绑定事件回调函数内部调用,具体的属性如下:
- key 返回发生变化的 key (即键名)
- oldValue 返回发生变化的 key 的原值(即改变前的值)
- newValue 返回发生变化的 key 的新值(即改变后的值)
- url 返回触发事件的 URL
- storageArea 返回触发事件的对象
这里需要提醒一点,Storage 的 事件需要在带有域名的目录下才能触发,即需要 Web 服务的支持,直接打开相应的文件并不能触发 Storage 事件,而 Storage 的 API 则无须这样。
接下来对上面的例子进行扩展,监听其中的 Web Storage ,你可以点击下面的 Demo 进行测试。这里问题就会出现了,在 Chrome 22 , Firefox 16 , Safari 5.1 中,直接改变表单中的值并提交是不会触发 "storage" 事件,但当用户打开两个 Demo 标签,改变其中一个标签中表单的值并提交,另一个页面反而会触发事件。事实上在较低版本的这三款浏览器中也会出现这个情况,这似乎是这三款浏览器对于 Web Storage 的处理机制并不完善。也因为这样,Kayo 并不建议在实际开发中利用 "storage" 事件。
监听 storage 事件
function triggerEvent(e){ var tips = 'key:' + e.key + ', newValue:' + e.newValue + ', oldValue:' + e.oldValue + ', url:' + e.url + ', storageArea:' + e.storageArea; alert(tips); } window.addEventListener('storage', triggerEvent, true);
完整 Demo 。
七. 不足之处
Web Storage 虽然功能强大并且使用也很方便,但实际上它仍存在一些问题,除了上面有提及的浏览器支持仍存在不足外,安全问题也是开发者必须注意的重要问题。W3C 为开发者列出了以下三点安全问题:
1. DNS 欺骗攻击 (DNS spoofing attacks)
因为一些潜在的 DNS 欺骗攻击,Web Storage 无法保证发出请求的脚本所在域是当前的域,这意味着域 A 中嵌入域 B 的脚本,该脚本可以访问域 A 的 Web Storage 。为了尽量减轻这种情况发生,可以使用对页面 TLS 。使用 TLS 可以确保用户或软件代表真实使用者,这样其他页面需要使用能确定它们来自同一域的 TLS 证书才可以访问 storage 。
2. 跨目录攻击 (Cross-directory attacks)
若不同的用户共享使用一个域名,例如几位用户共用 abc.com 域名,所有人都将会共享 abc.com 下的 storage 对象,但没有任何特性可以限制特定访问路径。因此不建议共享域名的用户使用 Web Storage ,这样可以避免域名下的其他用户可以阅读你的 Web Storage 甚至重写它们。
即使可以限制访问的路径,也可以利用 DOM 脚本安全模型轻松地跳过这保护并访问数据。当然,Web Storage 是存储在本地端,如果这些共享域名的用户之间不会接触到其他人的本地端,那这个问题就不用担心了。
3. 实施风险 (Implementation risks)
当使用这些持久化存储特性时,会让有不好意图的网站跨域阅读到这些数据,甚至还会让这些网站写入信息,然后再跨域利用这些信息。
直白的说,让第三方网站写入持久性的数据可能会导致信息泄漏,例如:一个域上的一个用户购买清单可以被另一个域作为定向广告。
最后关于兼容性的问题,由于移动端上的主流浏览器(Android, IOS 的系统浏览器, opera 等现代浏览器)对于 Web Storage 乃至很多 HTML5 的特性支持已经很完善和统一,如果你是利用这项特性开发 Web Apps ,兼容性的问题反而不用过于担心,这也是使用 HTML5 开发 Web Apps 的重要优势。
因此,虽然 Web Storage 仍会存在一些不足,但从综合的角度考虑,Web Storage 已经具有很好的实用价值。利用 Web Storage 保存一些非机密的设置信息无疑是 Web Apps 开发中一个很好的选择。
原文由 Kayo Lee 发表,原文链接:http://kayosite.com/web-app-by-jquery-mobile-and-html5-web-storage.html