这篇我们讲跨域的几个冷门方法,如果想从头开始可以点击跨了个域第一篇;
postMessage大法:跨文档信息传送(cross-document messaging),有时简称为XMD,指的是在来自不同域的页面间传递信息。
XDM的核心是postMessage()方法。对于XDM而言,通常指的是包含在当前页面中的<iframe>元素,或者由当前页面弹出的窗口。
这个页面所在的位置是http://127.0.0.1/demo.html,引入了http://127.0.0.1/test.html,不造成跨域,但为的就是先看不跨越正常使用的效果
// http://127.0.0.1/demo.html
<iframe src="http://127.0.0.1/test.html" frameborder="0" id="iframe"></iframe>
<script>
var haha = 1234;
window.onload = function () {
var iframeWindow = document.getElementById('iframe').contentWindow; // 获取引用window
console.log(iframeWindow, iframeWindow.myName);
iframeWindow.postMessage({ name: 'mike' }, 'http://127.0.0.1'); // 发送信息
}
</script>
// http://127.0.0.1/test.html
<script>
var myName = 'child';
window.addEventListener('message', function (event) {
console.log(event.data); // 传输的信息
console.log(event.origin); // 发送信息的文档所在的域
console.log(event.source, event.source.haha); // 发送信息的window对象
// 可以再利用event.socuce.postMessage一次,但这样发送的,当进入event.source时,window对象就会变成自己
})
</script>
现在看浏览器所输出
可以从打印中看到可以拿到对应的window对象,也输出了传递的值;
现在看跨域的情况:引入不同端口的页面
// http://127.0.0.1/demo.html
<iframe src="http://127.0.0.1:361/src/index2.html" frameborder="0" id="iframe"></iframe>
<script>
var haha = 1234;
window.onload = function () {
var iframeWindow = document.getElementById('iframe').contentWindow; // 获取引用window
console.log(iframeWindow, iframeWindow.nam);
iframeWindow.postMessage({ name: 'mike' }, 'http://127.0.0.1:361'); // 发送信息
}
</script>
// http://127.0.0.1:361/src/index2.html
<script>
var myName = 'child';
window.addEventListener('message', function (event) {
console.log(event.data); // 传输的信息
console.log(event.origin); // 发送信息的文档所在的域
console.log(event.source, event.source.haha); // 发送信息的window对象
// 可以再利用event.socuce.postMessage一次,但这样发送的,当进入event.source时,window对象就会变成自己
})
</script>
浏览器输出:
记住这个信息并不是不能达到跨域,只是不让你去访问对应的window对象了而已,我们把window都删掉
// http://127.0.0.1/demo.html
<iframe src="http://127.0.0.1:361/src/index2.html" frameborder="0" id="iframe"></iframe>
<script>
var haha = 1234;
window.onload = function () {
var iframeWindow = document.getElementById('iframe').contentWindow; // 获取引用window
iframeWindow.postMessage({ name: 'mike' }, 'http://127.0.0.1:361'); // 发送信息
}
</script>
// http://127.0.0.1:361/src/index2.html
<script>
var myName = 'child';
window.addEventListener('message', function (event) {
console.log(event.data); // 传输的信息
console.log(event.origin); // 发送信息的文档所在的域
})
</script>
浏览器输出:
一样可以拿到传递的值,但跨域的限制就是:只能拿到传递的值,不能拿到window对象;你要是说那把window传递过去不就行了,其实还是会被浏览器拦截~
使用open打开的就不展示了,也是一样用postMessage传递,不跨越正常使用;跨域则不使用去获取对方的window则不报错;(还有一种情况是拿到对方的window,但却不用获取window上挂载的自定义变量)
这里顺带一提,如果我们使用a链接并且用_blank方式打开的窗口(同源),我们也可以在这个打开的窗口使用window.opener查看主页面的信息,虽然对访问有所限制(不能访问到挂载的自定义变量),但还是有漏网之鱼
比如我给你来个:opener.location = 'http://cf.qq.com/index.shtml',你就完全没心思学习,甚至想打cf!因为已经改变了你的主窗口跳转;
<a href="http://127.0.0.1/test.html" target="_blank" rel="noopener">哈哈</a>
我们可以使用rel="noopener"改变,让被打开窗口的opener变成null;
document.name+ iframe大法
这个方法会稍稍有点绕,但看好步骤就不那么难了;
记住,核心即为window.name,因为name有一个特性就是在不同页面或者不同域下加载后依旧存在,没有修改就不会发生变化!
觉得虚幻的同学可以试试随便打开一个页面后,开F12手动修改name,然后随便在本窗口打开别的页面(一定在本窗口打开,不能打开新窗口),然后你会发现这个窗口的name还是你刚刚设置的name~
首先准备三个页面:
主页面
proxy空页面(为了规避策略)
需要跨域的页面设置好name
// index2.html - 需要获取信息的页面设置好name
<script>
window.name = 'I am index2!';
</script>
<script>
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
var state = 0;
iframe.onload = function () {
if (state === 1) {
var data = iframe.contentWindow.name;
console.log(data) // 4.接着就拿到了需要的数据
iframe.contentWindow.close(); // 关闭window,页面就不会存在iframe框
document.body.removeChild(iframe); // 删除节点
} else if (state === 0) {
state = 1;
iframe.contentWindow.location = './proxy.html'; // 3.当加载完成后立即跳转成本服务器的一个页面(没有跨域问题)
}
};
iframe.src = 'http://localhost:361/src/index2.html'; // 1.这个是需要跨域的地址
document.body.appendChild(iframe); // 2.插入body后立即生效
</script>
剩下的还有 document.domain + iframe 跨域 location.hash + iframe 跨域没有介绍,这里也就不多介绍了~
这两个方法可以自行百度参考。我喜欢的还是够用就行~