跨域通信方法总结

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,代码如下:

var dosomething= function(data){
    alert(‘我是A.com域上的页面,可以被跨域的remote.js文件调用,远程js带来的数据是:‘ + data.result);
};
</script>
<script src="B.com/b.js"></script>
而B.com上的b.js文件代码如下:
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 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>
上述过程首先将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值。

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);

以上是关于跨域通信方法总结的主要内容,如果未能解决你的问题,请参考以下文章

跨域访问方法介绍--使用片段识别符传值

跨域问题总结

在tablayout片段之间进行通信[重复]

Ajax跨域通信方法?

iframe跨域通信方案

片段通信问题(尝试调用虚方法)