postMessage跨域实现localstorage跨域共享
浅谈postMessage跨域通信与localStorage实现跨域共享
我们可能有需要在多个域名之间共用同一个localStorage的需要
一、我们先测试不同域名之间的通信
1.有 child.html 如下,代码中 window.parent.postMessage(data,origin) 方法允许来自不同源的脚本采用异步方式进行通信,可以实现跨文本档、多窗口、跨域消息传递。接受两个参数:
- data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器支持任意类型的参数,部分浏览器只能处理字符串参数,所以在传递参数时需要使用JSON.stringify()方法对对象参数序列化。
- origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,只是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然也可以将参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
<!doctype html>
<html>
<head>
<style type="text/css">
html,body{
height:100%;
margin:0px;
}
</style>
</head>
<body style="height:100%;">
<div id="container" onclick="changeColor();" style="widht:100%; height:100%; ">
click to change color
</div>
<script type="text/javascript">
var container = document.getElementById('container');
// iframe接收消息,并把当前颜色发送给主页面
changeColor();
// 点击iframe时触发changeColor方法,把变化后的颜色发送给主页面
function changeColor() {
var color = container.style.backgroundColor;
if (color == 'rgb(204, 102, 0)')
color = 'rgb(204, 204, 0)';
else
color = 'rgb(204,102,0)';
container.style.backgroundColor = color;
console.log('start post color ..............');
window.parent.postMessage(color, '*');
}
</script>
</body>
</html>
2.然后在 main.html 中引入 child.html,window.addEventListener('message', function(e) { dosomething....}, false); 用来监听iframe 中发过来的消息
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div style="width:200px; float:left; margin-right:200px;border:solid 1px #333;">
<div id="color">Frame Color</div>
</div>
<div>
<iframe id="child" src="http://www.abc.com/child.html"></iframe>
</div>
<script type="text/javascript">
// 主页面监听message事件,初始化自身颜色
// 主页面监听message事件,处理自身变色
window.addEventListener('message', function(e) {
console.log('listen.....');
var color = e.data;
document.getElementById('color').style.backgroundColor = color;
}, false);
</script>
</body>
</html>
3.这时我们就可以看到效果了,如下图,当我们点击包含在main.html 中的 child.html页面时,main.html中的FrameColor也跟着变了

二、接下来我们实现跨域之间的localstorage共享
1.解决思路:在A域和B域下引入C域,所有的读写都由C域来完成,本地数据存在C域下; 因此 A哉和B域的页面必定要引入C域的页面; 当然C域最好是主域,原因后面会提到(在localstorage 不方便的情况下使用cookie);
- 【A域】【B域】需要读写时,通过postMessage 向【C域】发送跨哉消息,
- 【C域】监听跨域消息,在接到批定的消息时进行读写操作,
- 【C域】接到跨域消息时,如果是写入删除可以不做什么,如果是读取,就要先读取本域本地数据通过postMessage向父页面发送消息,
- 【A 域 / B 域】在读取【C域】数据时就需要监听来自【C域】的跨域消息
2.注意事项:
window.postMessage()方法,向【C域】发消息,应用iframe.contentWindow.postMessage() 这样iframe内的【C 域】才可以接到,
同理,【C域】向 【A 域B域】发消息时应用,window.parent.postMessage(),【A域、B域】的逻辑一定要在iframe 加载完成后进行。
3.代码:
【C域】页面如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex">
<title>cross domain</title>
</head>
<body>
<script>
;(function(doc,win,undefined){
var fn=function(){};
fn.prototype={
/*本地数据存储*/
setLocalCookie: function (k, v, t,domain) {
typeof window.localStorage !== "undefined" ? localStorage.setItem(k, v) :
(function () {
t = t || 365 * 12 * 60 * 60;
domain=domain?domain:".hc360.com";
document.cookie = k + "=" + v + ";max-age=" + t+";domain="+domain+";path=/";
})()
},
getLocalCookie: function (k) {
k = k || "localDataTemp";
return typeof window.localStorage !== "undefined" ? localStorage.getItem(k) :
(function () {
var all = document.cookie.split(";");
var cookieData = {};
for (var i = 0, l = all.length; i < l; i++) {
var p = all[i].indexOf("=");
var dataName = all[i].substring(0, p).replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"");
cookieData[dataName] = all[i].substring(p + 1);
}
return cookieData[k]
})();
},
clearLocalData: function (k) {
k = k || "localDataTemp";
typeof window.localStorage !== "undefined" ? localStorage.removeItem(k) :
(function () {
document.cookie = k + "=temp" + ";max-age=0";
})()
},
init:function(){
this.bindEvent();
},
bindEvent:function(){
var _this=this;
win.addEventListener("message",function(evt){
if(win.parent!=evt.source){return}
var options=JSON.parse(evt.data);
if(options.type=="GET"){
var data=tools.getLocalCookie(options.key);
win.parent.postMessage(data, "*");
}
options.type=="SET"&&_this.setLocalCookie(options.key,options.value);
options.type=="REM"&&_this.clearLocalData(options.key);
},false)
}
};
var tools=new fn();
tools.init();
})(document,window);
</script>
</body>
</html>
【A域】页面如下:我们再C中设置了 localStorage
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div style="width:200px; float:left; margin-right:200px;border:solid 1px #333;">
<div id="color">Frame Color</div>
</div>
<div>
<iframe id="child" src="http:///c.html"></iframe>
</div>
<script type="text/javascript">
window.onload = function() {
console.log('set key value......................')
window.frames[0].postMessage(JSON.stringify({type:"SET",key:"key",value:"value"}),'*');
}
</script>
</body>
</html>

上传A、C之后我们见到效果如上图
【B域】页面如下:我们读取A中设置的 localStorage
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div style="width:200px; float:left; margin-right:200px;border:solid 1px #333;">
<div id="color">Frame Color</div>
</div>
<div>
<iframe id="child" src="http:///c.html"></iframe>
</div>
<script type="text/javascript">
window.onload = function() {
console.log('get key value......................')
window.frames[0].postMessage(JSON.stringify({type:"GET",key:"key"}),'*');
}
window.addEventListener('message', function(e) {
console.log('listen.....');
var data = e.data;
console.log(data);
}, false);
</script>
</body>
</html>
访问c打开console见到效果如下

至此我们实现了跨域 localStorage 的读取和删除。


浙公网安备 33010602011771号