Storage

luics edited this page Feb 24, 2014 · 36 revisions
Clone this wiki locally

跨终端跨域的存储方案
2013 kissy 组件大赛冠军 by 鬼道

最初的需求

  1. 天猫工具栏部署在大部分天猫页面左侧,有诸如此类的需求:
    • 多个页面(多个域)需要保存工具栏的显示状态
    • 某些消息在指定时间间隔内显示
    • 存储某些信息的删除记录
    • 其他需要在多个页面间保持的数据
  2. 天猫页面
    • 天猫多数页面具有自己的子域
    • 大部分现有页面为 tmall.com 域、国际站页面属于 tmall.hk 域

方案

  1. 存储方案
    • Store.js:localStorage(标准浏览器 + ie 8+) + userData (ie 6/7)
  2. 跨域方案
    • 使用 iframe 加载代理页,数据存储在代理页所在的域下
    • 需要实现宿主页与代理页之间的通信
    • postMessage(标准浏览器 + ie 8+) + window.name(ie 6/7)

以下对现有技术方案做分析

跨终端存储

存储介质

应考虑

  1. 首选 localStorage
  2. userData 可以做 ie 6/7 的兼容方案

不考虑

  1. flash 方案,Adobe 已经宣布放弃对移动浏览器中的 flash 支持,并且 iOS 中无 flash 支持
  2. cookie 存储上限只有 4KB,且会加重网络负担,cookie 会被发送到作用域之内的所有http请求,包括js请求,css请求,图片请求,很多异步的请求等等,如果按照10亿 pv 计算,1 byte cookie 大约会增加 5.590 G 的流量,1 KB cookie 就 会增加 5.590 T 流量。 Cookie 不适合作为存储载体

参考
1. https://github.com/bebraw/jswiki/wiki/Storage-libraries
2. http://www.html5rocks.com/en/tutorials/offline/storage/
3. http://www.css88.com/archives/3717

存储上限

  1. localStorage 5MB,有浏览器差异,详见 http://dev-test.nemikor.com/web-storage/support-test/
  2. userData 单个文件128KB,单个域1024KB,详见 http://msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx

参考
1. https://github.com/marcuswestin/store.js/wiki#storage-limits

跨域通信

跨域本质上还是通信问题,或说建立通信通道。下表罗列了最常见的10种 跨域通信方法,我们依据以下原则选择适合 Storage 的跨域通信方案:

  1. iframe 场景下使用
  2. 不改写 document.domain

    前端可能会用 document.domain 进行环境判断,而改写 document.domain 在复杂系统中很容易产生隐患,这种隐患都是开关级别的通常比较严重;即使没有这种隐患, document.domain 改写也只能在同一个主域下进行,对于不同主域(如 a.com和b.com)的情况就无能为力了。

  3. 跨子域、跨主域
  4. 不使用 Flash

参考
1. http://www.woiweb.net/10-cross-domain-methods.html
2. http://zciii.com/blogwp/crossdomain/

通信形式 iframe 场景 不改写
document.domain
跨子域主域 不使用 Flash
JSONP 单向通信
window.name 单向通信
(IE6/7 例外)
CORS 单向通信
Flash URLLoader 单向通信
Server Proxy 单向通信
document.domain 双向通信
FIM 双向通信
Flash LocalConnection 双向通信
postMessage 双向通信
Cross Frame 双向通信

满足所有条件的只有 postMessage、window.name (只用在 IE6、7)。FIM 会改写浏览器地址有潜在的风险,Cross Frame 需要代理页部署在宿主也所在的域,实施成本过高也不考虑。

异常处理

Storage 的所有方法都只有 success 一个回调。是基于这样的思路「电梯永远不会坏」,电梯即使在断电或机械故障时并不影响人们通行;Storage 也是如此,即使代理页或其他异常导致不能正常存取数据,那么 success 回调的参数为undefined,并不会阻塞回调的触发。

IE 6/7 兼容处理

尽管是要退出历史舞台的平台,为了能够让 Storage 兼容 IE6/7 着实废了一番功夫。使用 window.name 进行跨域通信首先要解决的就是并发请求的问题,我们利用队列机制,确保请求的有序进行。

安全性

由于数据存储在代理页(proxy)所在的域,数据可被所有能够加载代理页的宿主页面访问。所以保证安全关键在于服务器端控制代理页的访问来源。

资源

  1. http://dev-test.nemikor.com/web-storage/support-test/ 这篇是各浏览器存储差异
  2. http://www.css88.com/archives/3717 这篇尾部有 localstorage api 的差异
  3. http://www.html5rocks.com/en/tutorials/offline/storage/ 这篇谈得比较深入一些
  4. https://github.com/marcuswestin/store.js 比较成熟和流行的封装
  5. https://github.com/bebraw/jswiki/wiki/Storage-libraries 更多库