设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 创业者 数据 手机
当前位置: 首页 > 站长学院 > MySql教程 > 正文

如何使用localstorage代替cookie实现跨域共享数据问题(3)

发布时间:2020-05-12 02:22 所属栏目:115 来源:站长网
导读:2,send方法返回一个promise对象,如果iframe已经onload成功,则直接调用postHandle方法进行postMessage操作,如果iframe还在加载中,则把当前的操作推到iframeBeforeFuns数组中,用函数包裹,等待iframe onload结

2,send方法返回一个promise对象,如果iframe已经onload成功,则直接调用postHandle方法进行postMessage操作,如果iframe还在加载中,则把当前的操作推到iframeBeforeFuns数组中,用函数包裹,等待iframe onload结束后统一调用,函数包裹的也是postHandle方法。

3,postHandle方法,在发送请求前包装data,生成cbid,origin,action和args,cbs对象保存了每个cbid下的resolve和reject,等待子页面的postMessage返回后处理。因为postMessage不能保留引用,不能传函数,所以这里选择这个方法来进行关联。

4,constructor比较好理解,当这个类被初始化的时候,我们定义了我们需要的一些options的属性,创建iframe,然后监听message事件,处理子页面返回的消息。

5,在父页面的message事件中,我们要校验,给我发消息的必须是我打开的这个窗口iframe,否则报错,然后根据data中的err标识来让cbs中的resolve和reject进行执行。

6,createIframe方法中,iframe onload中的回调处理创建前 缓存的调用方法,这里注意使用了domready,因为可能body还没解析就会进行sdk的执行。

下面是child部分的代码:

class iframe { set(key, val, options, origin) { //检查val大小,不能超过20k. val = val.toString(); val = this.lz ? lzstring.compressToUTF16(val) : val; var valsize = sizeof(val, 'utf16'); //localStorage 储存使用utf16编码计算字节 if (valsize > this.maxsize) { return { err: 'your store value : "' + valstr + '" size is ' + valsize + 'b, maxsize :' + this.maxsize + 'b , use utf16' } } key = `${this.prefix}_${key},${new url(origin).origin}`; var data = { val: val, lasttime: Date.now(), expire: Date.now() + options.expire }; store.set(key, data); //大于最大储存个数,删除最后一次更新的 if (store.size() > this.storemax) { var keys = store.keys(); keys = keys.sort((a, b) => { var item1 = store.get(a), item2 = store.get(b); return item2.lasttime - item1.lasttime; }); var removesize = Math.abs(this.storemax - store.size()); while (removesize) { store.remove(keys.pop()); removesize--; } } return { ret: data } } get(key, options) { var message = {}; var keys = store.keys(); var regexp = new RegExp('^' + this.prefix + '_' + key + ',' + options.domain + '$'); message.ret = keys.filter((key) => { return regexp.test(key); }).map((storeKey) => { var data = store.get(storeKey); data.key = key; data.domain = storeKey.split(',')[1]; if (data.expire < Date.now()) { store.remove(storeKey); return undefined; } else { //更新lasttime; store.set(storeKey, { val: data.val, lasttime: Date.now(), expire: data.expire }); } data.val = this.lz ? lzstring.decompressFromUTF16(data.val) : data.val; return data; }).filter(item => { return !!item; //过滤undefined }); return message; } clear(key, origin) { store.remove(`${this.prefix}_${key},${origin}`); return {}; } clearOtherKey() { //删除不合法的key var keys = store.keys(); var keyReg = new RegExp('^' + this.prefix); keys.forEach(key => { if (!keyReg.test(key)) { store.remove(key); } }); } constructor(safeDomain, lz) { supportCheck(); this.safeDomain = safeDomain || /.*/; this.prefix = '_cros'; this.clearOtherKey(); if (Object.prototype.toString.call(this.safeDomain) !== '[object RegExp]') { throw new Error('safeDomain must be regexp'); } this.lz = lz; this.storemax = 100; this.maxsize = 20 * 1024; //字节 addEvent(window, 'message', (evt) => { var data = JSON.parse(evt.data); var originHostName = new url(evt.origin).hostname; var origin = evt.origin, action = data.action, cbid = data.cbid, args = data.args; //合法的广播 if (evt.origin === data.origin && this.safeDomain.test(originHostName)) { args.push(origin); var whiteAction = ['set', 'get', 'clear']; if (whiteAction.indexOf(action) > -1) { var message = this[action].apply(this, args); message.cbid = cbid; window.top.postMessage(JSON.stringify(message), origin); } } else { window.top.postMessage(JSON.stringify({ cbid: cbid, err: 'Illegal domain' }), origin); } }); } }

代码也不多,这里简单说一下各个方法的用处和组织关系:

1,constructor部分,上面的类里也进行浏览器特性支持检查,然后定义了store的prefix值,最大个数和每一个key的maxsize等属性。然后我们创建message通道,等待父页面调用。

2,在message中,我们对发送广播的origin进行检查,然后对调用的方法进行检查,调用对应的set,get,clear方法,然后把执行的结果拿到,绑定cbid,最后再postMessage发送回父页面。

3,clearOtherKey 删除不合法的一些store数据,只保留符合格式的数据。

4,set方法中对每一条的数据做size校验,lz压缩,保存的data中包含了val,key,过期时间以及更新时间(用于LRU计算)。

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读