iframe的src可以引入任何源,但是二者如果想通信的话,必须是同源。
随着业务的发展,自然地会有一些公共的业务被抽离成为公共组件供各个项目使用。但是由于各个项目用到的技术栈都有所不同,所以这个公共组件就不能方便地被引用了。为解决这个问题,我们把这个组件写成了单独的页面挂到一个域名下,其他项目采用iframe或者webview的方式去加载这个页面,从而实现功能的简单复用。
不过这过程中也产生了很多问题,比如通信跨域。以下我将会介绍我遇到的跨域问题以及一些解决方法。
最近在做一个需求,需要用iframe引入一个别人封装好的类似视频播放器的东西。iframe里面有一个全屏的按钮,点击后需要页面让iframe全屏,由于受到同源策略的限制,iframe无法告诉页面全屏。
document.domain
是 JavaScript 中的一个属性,用于设置或获取当前页面的域名。
它的作用是允许在同一个域名下的不同子域之间进行跨域通信。默认情况下,不同子域之间的 JavaScript 代码是无法直接访问彼此的属性和方法的,这是出于安全考虑的限制。但是,如果将它们的 document.domain
设置为相同的值,就可以解除这个限制。
使用方法很简单,只需要在 JavaScript 中设置 document.domain
属性为相同的值即可。例如:
// 在父页面中设置 document.domain
document.domain = "example.com";
// 在子页面中也设置 document.domain
document.domain = "example.com";
这样,父页面和子页面就可以通过 JavaScript 代码进行跨域通信了。
需要注意的是,为了使用 document.domain
进行跨域通信,域名必须满足以下条件:
否则,浏览器将不允许使用 document.domain
进行跨域通信。
设置完之后,在a页面的window上挂载使iframe全屏的方法
// a页面
window.toggleFullScreen = () => {
// do something
}
在b页面上可以直接获取到a页面的window对象并直接调用
// b页面
window.parent.toggleFullScreen()
但是这个值的设置也有一定限制,只能设置为当前文档的上一级域或者是跟该文档的URL的domain一致的值。如url为a.demo.com,那domain就只能设置为demo.com或者a.demo.com。因此,设置domain的方法只能用于解决主域相同而子域不同的情况。
window.postMessage方法可以安全地实现跨源通信,写明目标窗口的协议、主机地址或端口就可以发信息给它。
// b页面
parent.postMessage(
value,
"http://a.demo.com"
);
// a页面
window.addEventListener("message", function( event ) {
if (event.origin !== 'http://b.demo.com') return;
toggleFullScreen()
});
为了安全,收到信息后要检测下event.origin判断是否要收信息的窗口发过来的。
通过以上的方法,我们就可以和iframe自由通信啦。
参考:iframe跨域的几种常用方法:https://juejin.cn/post/6844903831973675015