跨域通信方法总结
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跨域通信方法总结相关的知识,希望对你有一定的参考价值。
本文总结了5种较常见的跨域通信方法,如下:
1)jsonp
2)CORS(Cross OriginResource Sharing,跨源资源共享)
3)主域相同可以设置document.domain
4)利用window.name实现跨域
5)利用window.name实现跨域
jsonp
讲解jsonp之前先看一个例子:假设域A.com上有一个页面a.html,代码如下:
而B.com上的b.js文件代码如下:var dosomething= function(data){ alert(‘我是A.com域上的页面,可以被跨域的remote.js文件调用,远程js带来的数据是:‘ + data.result); }; </script> <script src="B.com/b.js"></script>dosomething({"result":"我是远程js带来的数据"});运行a.html,显然会弹出弹框,显示接受到了远程js带来的数据。
以上代码在A域上声明了处理数据的函数,在B域上将json数据传入此函数,实现调用。但是,我们如何在B域上知道A域定义的函数名呢,这就需要我们在请求脚本文件时将函数名一同发送给B,告诉B“我想要一段调用XXX函数的js代码,请你返回给我”,B获取此函数名,并将数据传入此函数名中进行调用,而这就是jsonp的原理。为了更通用也灵活的使用此方案,可以采用动态创建script的方式,从而避免手动填写script地址。以下看看a.html如何实现:
var dosomething = function(data){ //处理数据 }; // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码) var url = "http://B.com/b.php?callback=dosomething"; // 创建script标签,设置其属性 var script = document.createElement(‘script‘); script.setAttribute(‘src‘, url); // 把script标签加入head,此时调用开始 document.getElementsByTagName(‘head‘)[0].appendChild(script);假设B域的中json数据在b.php中,则b.php的实现大致如下:
<?php $callback = $GET[‘callback‘];//获得函数名 $data = array(‘a‘,‘b‘,‘c‘);//获得数据 echo $callback.‘(‘.json_encode($data).‘)‘;//执行函数,并输出结果 ?>这样,我们就将获得的数据传入了约定的函数中,jsonp的过程也就顺利完成。
CORS(Cross OriginResource Sharing,跨源资源共享)
由于同源策略,XHR无法访问其他域的资源。CORS的主要思想就是,使用自定义的HTTP头部告诉服务器,可以接受指定域的访问,也就相当于在约定好的情况下临时接触了特定域的同源策略。
假设A.com域要访问B.com的数据,只需在B.com做如下设置即可
header("Access-Control-Allow-Origin:http://A.com");表示B.com可以接受来自A.com的访问请求,相当于临时接触了同源限制,接下来的访问操作就和不跨域一样。
主域相同可以设置document.domain
(此访问只适用于主域相同,而子域不同的场景。比如www.A.com和script.A.com)
此方法只需要将如上所述的两个域中的页面设置相同的document.domain,并在www.A.com/a.html中创建一个iframe,将此iframe的地址设置为script.A.com域地址,以此来操控script.A.com。www.A.com/a.html的代码:
document.domain = ‘A.com‘; var ifr = document.createElement(‘iframe‘); ifr.src = ‘http://script.A.com/b.html‘; ifr.style.display = ‘none‘; document.body.appendChild(ifr); ifr.onload = function(){ var doc = ifr.contentDocument || ifr.contentWindow.document; // 在这里操纵b.html };script.A.com/b.html的代码
document.domain = ‘A.com‘;利用window.name实现跨域
window.name有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。比如:
有一个a.html,代码如下:
window.name=‘我是a.html的Window.name‘; window.location ="b.html";
b.html代码如下:
alert(window.name);运行a.html,会跳转到b.html,并弹出弹窗显示”我是a.html的Window.name“。也就是只要b.html不对window.name做修改,其值都是a.html中设置的window.name值。
仔细回顾一下以上过程,我们会发现,可以利用这个window.name来传输我们需要在不同域中传输的数据。比如A.com/a.html要访问B.com/b.html数据,那么可以在B.com/b.html将数据放在window.name中:
window.name=‘我是要传输的数据‘;但在A.com/a.html,显然不能通过window.location来跳转到B.com/b.html,我们希望可以不用跳转就可以获得数据。此时我们需要借助一个隐藏的媒人iframe,利用iframe去获取B.com/b.html的数据,然后A.com/a.html再去获取iframe得到的数据。
上述过程首先将iframe的src设置为B.com/b.html,这样就可以获取B.com/b.html的window.name,也就是需要的数据。然后,如果A.com/a.html想要获得此数据,必须是的iframe与A.com同域,因此采用一个与A.com同域的代理页面A.com/proxy.html去获得此时iframe的contentWindow.name值,也就是之前获得了之后一直没有改变的window.name值。<iframe id="proxy" src="B.com/b.html" style="display: none" onload =loadfn></iframe> <script> var state = 0; var iframe = document.getElementById(‘proxy‘); loadfn = function() { if (state === 1) { var data = iframe.contentWindow.name; // 读取数据 alert(data); //弹出‘我是要传输的数据‘ } else if (state === 0) { state = 1; iframe.src = "http://A.com/proxy.html";//设置的代理文件,只要与A.com同域即可 } }; </script>HTML5的window.postMessage实现跨域
window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源。
window.postMessage(message,targetOrigin) 中的window指的接受数据的window对象,一般是页面中iframe的contentWindow属性,第一个参数message为要发送的消息,类型只能为字符串;第二个参数targetOrigin表示接收数据的那个window对象所在的域。
比如A.com/a.html要访问B.com/b.html的数据,则由B.com/b.html向A.com/a.html发送数据,B.com/b.html的实现如下:
<iframe id="ifr" src="A.com/a.html"></iframe> <script type="text/javascript"> window.onload = function() { var ifr = document.getElementById(‘ifr‘); var targetOrigin = ‘http://A.com/a.html‘; ifr.contentWindow.postMessage(‘我是数据‘, targetOrigin); }; </script>在A.com/a.html中监听message事件,从而获得发送过来的数据:
window.addEventListener(‘message‘, function(event){ // 通过origin属性判断消息来源地址 if (event.origin == ‘http://A.com/a.html ‘) { alert(event.data); // 弹出"我是数据" } }, false);
以上是关于跨域通信方法总结的主要内容,如果未能解决你的问题,请参考以下文章