在项目中遇到页面中嵌入IFrame(主页面和框架页为不同域名)时,由于同源策略,主页面和IFrame内页无法通讯的问题。
同源策略是一个很重要的安全理念,它在保证数据的安全性方面有着重要的意义。同源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和操作另外一个域的绝大部分属性和方法。那怎样是相同的域呢?当两个域具有相同的协议(如http), 相同的端口(如80),相同的host(如www.example.org),那么我们就可以认为它们是相同的域。
查找并实践了几种方法,在这里记录一下。
第一种:修改document.domain
跨域的不同框架之间(父框架和同辈框架),是能够获取到彼此的window对象的,但是却不能获取到window对象的属性和方法。在父窗口以及框架页内设定document.domain = document.domain; 后,两个页面间就可以透过拿到的window对象去互相调用对方方法或属性。
这种方法适合主域相同,而子域不同的场景。这里有一段解释: https://developer.mozilla.org...
A page may change its own origin with some limitations. A script can set the value of document.domain to its current domain or a superdomain of its current domain. If it sets it to a superdomain of its current domain, the shorter domain is used for subsequent origin checks. For example, assume a script in the document at http://store.company.com/dir/... executes the following statement:
document.domain = "company.com";
After that statement executes, the page can pass the origin check with http://company.com/dir/page.html (assuming http://company.com/dir/page.html sets its document.domain to "company.com" to indicate that it wishes to allow that - see document.domain for more). However, company.com could not set document.domain to othercompany.com since that is not a superdomain of company.com.
The port number is kept separately by the browser. Any call to the setter, including document.domain = document.domain causes the port number to be overwritten with null. Therefore one cannot make company.com:8080 talk to company.com by only setting document.domain = "company.com" in the first. It has to be set in both so that port numbers are both null.
第二种方法:使用window.postMessge
父页面http://localhost:8081/
<body>
<h1>This is synesiss app</h1>
<input type="button" name="" value="Call API" onclick="callAPI()">
<iframe id="childFrame" src="http://localhost:8888/" width="" height=""></iframe>
</body>
<script type="text/javascript">
document.domain = document.domain;
function callAPI(){
let receiver = document.getElementById("childFrame").contentWindow;
receiver.postMessage("callAPI", "http://localhost:8888/");
}
</script>
子页面http://localhost:8888/
<script>
window.onload = function(){
window.addEventListener('message', function(event){
if (event.origin !== "http://localhost:8081")
return;
if(event.data == "callAPI") {
// do API...
}
});
}
</script>
参考资源: 跨域资源共享的10种方式
新手学跨域之iframe