最近遇到一个问题,就是不同源的两个网页之间进行localstorage
或者cookie
的共享。
上周其实遇到过一次,觉得麻烦就让后端换了种方式处理了,昨天又遇到了同样的问题。
使用场景
比如从网页A通过iframe
跳转到网页B,而且这两个网页之间协议 域名 端口 只要有一个不一样,则为不同源的网页。
而且我遇到的情况是:正式环境下网页A和网页B是一级域名相同,二级域名不同,比如网页A:a.xxx.com,网页B:b.xxx.com
不同源的网页直接通过localStorage/sessionStorage/Cookies是无法实现共享的
localStorage/sessionStorage/Cookies不同页面值共享情况:https://blog.csdn.net/aliujiujiang/article/details/113117198
上面这篇文章中提到了:localStorage/sessionStorage/Cookies不同页面值共享是不同实现的。
1、不同浏览器无法共享localStorage和sessionStorage的值。
2、相同浏览器下,并且是同源窗口(协议、域名、端口一致),不同页面可以共享localStorage,Cookies值,通过跳转的页面可以共享sessionStorage值。
3、关于sessionStorage,通常说sessionStorage关闭页面即消失,但是通过跳转的页面可以共享sessionStorage值,跳转有多种方式:
(1) <a href="同源页面" target="_self">跳转</a> //原窗口
(2) <a href="同源页面" target="_blank">跳转</a> //新开窗口
(3) window.location.href = '同源页面' //原窗口
(4) window.location.replace('同源页面') //原窗口
(5) window.open('同源页面') //新开窗口
(6) this.$router.push({path: '同源页面'}) //通过路由跳转共享值
app端通过原生方法更换webView实现跳转,这种方式不能共享sessionStorage,原窗口跳转的页面传递sessionStorage,改变存储值会相互影响,新开窗口跳转方式传递sessionStorage,改变存储值互不影响
不同源且需要实现localStorage/sessionStorage/Cookies共享的解决办法——postMessage
使用postMessage来实现不同源网页的存储共享,则需要使用iframe
标签。且必须明确的知道谁是子页面,谁是父页面。
解决步骤1:区分子页面和父页面
注意:包含iframe
标签的才是父页面,而iframe
标签中的src
指定的页面才是子页面。
下面的代码是一个父页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<iframe
width="1000px"
height="460px"
id="childView"
src="http://115.236.37.xxxx:xxxx/#/companyDetailOut?name=%E5%AE%89%E7%9F%B3%E6%96%B0%E8%83%BD%E6%BA%90%20%28%E6%B7%B1%E5%9C%B3%29%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8"
></iframe>
<script>
window.onmessage = (e) => {
console.log(111);
console.log(2222, e);
localStorage.setItem('111token', e.data);
localStorage.setItem('222token', 4444444);
let token1 = localStorage.getItem('111token');
console.log(1, token1);
const childView = document.getElementById('childView');
//对象数据需序列化后才能被完整接收,否则接收的数据仅会展示[Object Object]
childView.contentWindow.postMessage(e.data, '*');
};
</script>
</body>
</html>
解决步骤2:父页面接收子页面的数据——window.onmessage
其中的script
代码是关于父页面接收子页面传过来的数据,并且通过localstorage存储到父页面的存储中
window.onmessage = (e) => {
console.log(111);
console.log(2222, e);
localStorage.setItem('111token', e.data);
localStorage.setItem('222token', 4444444);
};
通过控制台中的应用程序,可以看到localstorage下是有两个源的:
通过上面的截图,可以看到两个页面的localstorage是不一样的,通过iframe标签嵌套的页面,也无法共享。图中也提示到子页面是第三方的,位于顶级网站之外。
解决步骤3:父页面向子页面发送数据——window.子页面.postMessage
const childView = document.getElementById('childView');//获取到子页面
//对象数据需序列化后才能被完整接收,否则接收的数据仅会展示[Object Object]
childView.contentWindow.postMessage(e.data, '*');
上面代码中的e.data
就是父页面向子页面发送的内容,可以是对象,如果是对象,则需要通过JSON.stringify(对象)
进行转化
第二个参数:就是接收的源,如果是同源的,或者一级域名相同的,则可以在此处进行设置。因为我这边的情况是完全不同源,则可以写成*不进行任何的限制。
解决步骤4:子页面发送数据到父级页面
window.parent.postMessage(
// window.parent获取父窗口,给父窗口发送信息
token,//要传递的数据,如果是对象,则需要通过JSON.stringify(对象)转化
'*'
);
解决步骤5:子页面监听父页面传递过来的数据
//监听获取的信息
window.onmessage = (e) => {
console.log('回显内容', e);
};
```
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/aae4c331bcf84c65807fd1d3e8c58655.png)
# 我要的效果
子页面中的接口需要token才能够正常请求,子页面中的localstorage中是存有token的,是存储到http://115.236.37.xx:xxx中的。父页面中需要加载子页面,通过iframe标签加载后,子页面通过localstorage获取到的token只能是父页面的,而不是子页面中的。
所以我通过子页面将localstorage中的token通过postmessage传递给父页面,然后父页面通过window.onmessage接收到内容后,通过localstorage存储到父页面中的localstorage中。则此时的子页面通过locastorage就可以拿到token了。
相当于是iframe嵌入的子页面获取子页面的token拿不到,只能拿到父页面的token,所以在父页面存储一下而已。
完成!!!多多积累,多多收获!!