-
Notifications
You must be signed in to change notification settings - Fork 29
Storage
luics edited this page Feb 24, 2014
·
36 revisions
跨终端跨域的存储方案
2013 kissy 组件大赛冠军 by 鬼道
- 天猫工具栏部署在大部分天猫页面左侧,有诸如此类的需求:
- 多个页面(多个域)需要保存工具栏的显示状态
- 某些消息在指定时间间隔内显示
- 存储某些信息的删除记录
- 其他需要在多个页面间保持的数据
- 天猫页面
- 天猫多数页面具有自己的子域
- 大部分现有页面为 tmall.com 域、国际站页面属于 tmall.hk 域
- 存储方案
- Store.js:localStorage(标准浏览器 + ie 8+) + userData (ie 6/7)
- 跨域方案
- 使用 iframe 加载代理页,数据存储在代理页所在的域下
- 需要实现宿主页与代理页之间的通信
- postMessage(标准浏览器 + ie 8+) + window.name(ie 6/7)
以下对现有技术方案做分析
应考虑
- 首选 localStorage
- userData 可以做 ie 6/7 的兼容方案
不考虑
- flash 方案,Adobe 已经宣布放弃对移动浏览器中的 flash 支持,并且 iOS 中无 flash 支持
- cookie 存储上限只有 4KB,且会加重网络负担,cookie 会被发送到作用域之内的所有http请求,包括js请求,css请求,图片请求,很多异步的请求等等,如果按照10亿 pv 计算,1 byte cookie 大约会增加 5.590 G 的流量,1 KB cookie 就 会增加 5.590 T 流量。 Cookie 不适合作为存储载体
参考
- localStorage 5MB,有浏览器差异,详见 http://dev-test.nemikor.com/web-storage/support-test/
- userData 单个文件128KB,单个域1024KB,详见 http://msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx
参考
跨域本质上还是通信问题,或说建立通信通道。下表罗列了最常见的10种 跨域通信方法,我们依据以下原则选择适合 Storage 的跨域通信方案:
-
iframe 场景下使用
-
不改写 document.domain
前端可能会用 document.domain 进行环境判断,而改写 document.domain 在复杂系统中很容易产生隐患,这种隐患都是开关级别的通常比较严重;即使没有这种隐患, document.domain 改写也只能在同一个主域下进行,对于不同主域(如 a.com和b.com)的情况就无能为力了。
-
跨子域、跨主域
-
不使用 Flash
参考
通信形式 | 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
,并不会阻塞回调的触发。
尽管是要退出历史舞台的平台,为了能够让 Storage 兼容 IE6/7 着实废了一番功夫。使用 window.name 进行跨域通信首先要解决的就是并发请求的问题,我们利用队列机制,确保请求的有序进行。
由于数据存储在代理页(proxy)所在的域,数据可被所有能够加载代理页的宿主页面访问。所以保证安全关键在于服务器端控制代理页的访问来源。
- http://dev-test.nemikor.com/web-storage/support-test/ 这篇是各浏览器存储差异
- http://www.css88.com/archives/3717 这篇尾部有 localstorage api 的差异
- http://www.html5rocks.com/en/tutorials/offline/storage/ 这篇谈得比较深入一些
- https://github.com/marcuswestin/store.js 比较成熟和流行的封装
- https://github.com/bebraw/jswiki/wiki/Storage-libraries 更多库