实现跨域的N种方法

从域提及

域: 域是WIN2K网络系统的安全性边界。咱们知道一个计算机网最基本的单元就是“域”,这一点不是WIN2K所独有的,但活动目录能够贯穿一个或多个域。在独立的计算机上,域即指计算机自己,一个域能够分布在多个物理位置上,同时一个物理位置又能够划分不一样网段为不一样的域,每一个域都有本身的安全策略以及它与其余域的信任关系。当多个域经过信任关系链接起来以后,活动目录能够被多个信任域域共享javascript

域树:域树由多个域组成,这些域共享同一表结构和配置,造成一个连续的名字空间。树中的域经过信任关系链接起来,活动目录包含一个或多个域树。域树中的域是经过双向可传递信任关系链接在一块儿。因为这些信任关系是双向的并且是可传递的,所以在域树或树林中新建立的域能够当即与域树或树林中每一个其余的域创建信任关系。这些信任关系容许单一登陆过程,在域树或树林中的全部域上对用户进行身份验证,但这不必定意味着通过身份验证的用户在域树的全部域中都拥有相同的权利和权限。由于域是安全界限,因此必须在每一个域的基础上为用户指派相应的权利和权限。php

域树中的域层次越深级别越低,一个“.”表明一个层次。
如域zhidao.baidu.com(百度知道)就比 baidu.com(百度)这个域级别低,由于它有两个层次关系,而baidu.com只有一个层次。html

何为跨域

默认状况下,,XHR 对象只能访问与包含它的页面位于同一个域中的资源。这种安全策略能够预防某些恶意行为。可是,实现合理的跨域请求对开发某些浏览器应用程序也是相当重要的。html5

只要协议、域名、端口有任何一个不一样,都被看成是不一样的域java

好比在http://www.a.com/a.js 页面向如下页面发送一个ajax请求,如下是其请求结果及说明ajax

URL 说明 是否容许通讯
http://www.a.com/b.js 同一域名下 容许
http://www.a.com:8000/a.js 同一域名,不一样端口 不容许
https://www.a.com/b.js 同一域名,不一样协议 不容许
http://script.a.com/b.js 主域相同,子域不一样 不容许
http://a.com/b.js 同一域名,不一样二级域名 不容许
http://www.a.com/b.js 不一样域名 不容许

对于端口和协议的不一样,只能经过后台来解决。咱们要解决的是域名不一样的问题json

如何跨域

(一) CORS(Cross-Origin Resource Sharing,跨源资源共享)跨域

1.CORS(Cross-Origin Resource Sharing,跨源资源共享)是W3C 的一个工做草案,定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,仍是应该失败。
2.实现此功能很是简单,只需由服务器发送一个响应标头便可。浏览器

浏览器支持状况:安全

  • IE 8+
  • Firefox 3.5+
  • Opera 12+
  • Safari 4+
  • Chrome 3+

假设咱们页面或者应用已在 http://www.a.com/ 上了,而咱们打算从 http://www.b.com 请求提取数据。通常状况下,若是咱们直接使用 AJAX 来请求将会失败,浏览器也会返回错误。
利用 CORS,http://www.b.com 只需添加一个标头,就能够容许来自 http://www.a.com 的请求。
下面是用php进行的设置,“*”号表示容许任何域向咱们的服务端提交请求:

header{"Access-Control-Allow-Origin: *"}

CORS的兼容性写法

function createCORSRequest(method, url){
        var xhr = new XMLHttpRequest();
        //非IE浏览器
        if ("withCredentials" in xhr){
            xhr.open(method, url, true);
        //IE浏览器
        } else if (typeof XDomainRequest != "undefined"){
            vxhr = new XDomainRequest();
            xhr.open(method, url);
        } else {
            xhr = null;
        }
        return xhr;
    }
    var request = createCORSRequest("get", "http://www.somewhere-else.com/page/");
    if (request){
        request.onload = function(){
            //对request.responseText 进行处理
        };
        request.send();
    }

(二) JSONP(JSON with Padding 填充式JSON 或参数式JSON)

在js中,咱们虽然不能直接用XMLHttpRequest请求不一样域上的数据时,可是在页面上引入不一样域上的js脚本文件倒是能够的,jsonp正是利用这个特性来实现的

JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。

例如:

<script type="text/javascript">
    function dosomething(jsondata){
        //处理得到的json数据
    }
</script>
<script src="http://example.com/data.php?callback=dosomething"></script>
  • 首先第一个script便签订义了一个处理数据的函数;
  • 而后第二个script标签载入一个js文件,http://example.com/data.php 是数据所在地址,可是由于是当作js来引入的,因此http://example.com/data.php 返回的必须是一个能执行的js文件;
  • 最后js文件载入成功后会执行咱们在url参数中指定的函数,而且会把咱们须要的json数据做为参数传入。因此php应该是这样的
<?php
    $callback = $_GET['callback'];//获得回调函数名
    $data = array('a','b','c');//要返回的数据
    echo $callback.'('.json_encode($data).')';//输出
    ?>

最终,输出结果为:dosomething(['a','b','c']);
从上面能够看出jsonp是须要服务器端的页面进行相应的配合的。

JSONP的优缺点
优势:

  • 它的兼容性更好,在更加古老的浏览器中均可以运行,不须要XMLHttpRequest或ActiveX的支持;
  • 可以直接访问响应文本,支持在浏览器与服务器之间双向通讯

缺点:

  • JSONP 是从其余域中加载代码执行。若是其余域不安全,极可能会在响应中夹带一些恶意代码,而此时除了彻底放弃JSONP 调用以外,没有办法追究。所以在使用不是你本身运维的Web 服务时,必定得保证它安全可靠。
  • 它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种状况,不能解决不一样域的两个页面之间如何进行JavaScript调用的问题。

(三) window.name

window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的全部的页面都是共享一个window.name的,每一个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的全部页面中的,并不会因新页面的载入而进行重置。

这里有三个页面:

a.com/app.html:应用页面。
a.com/proxy.html:代理文件,通常是一个没有任何内容的html文件,须要和应用页面在同一域下。
b.com/data.html:应用页面须要获取数据的页面,可称为数据页面。

app.html

<iframe src="b.com/data.html" id="iframe"></iframe>
<script>
    var iframe = document.getElementById("iframe");
    iframe.src = "a.com/proxy.html";//这是一个与a.com/app.html同源的页面
    iframe.onload = function(){
        var data = iframe.contentWindow.name; //取到数据
    }

</script>

data.html

<script>
    // 这里是要传输的数据,大小通常为2M,IE和firefox下能够大至32M左右
    // 数据格式能够自定义,如json、字符串
    window.name = "数据"
</script>

iframe首先的地址是b.com/data.html,因此能取到window.name数据;
可是iframe如今跟app.html并不一样源,app.html没法获取到数据,因此又将iframe的连接跳转至a.com/proxy.html这个代理页面,如今app.html跟iframe就同源了。

注意:iframe由b.com/data.html跳转到a.com/proxy.html页面,window.name的value是不变的

获取数据之后销毁这个iframe,释放内存;这也保证了安全(不被其余域frame js访问)

<script type="text/javascript">
    iframe.contentWindow.document.write('');
    iframe.contentWindow.close();
    document.body.removeChild(iframe);
</script>

(四) document.domain + iframe

对于主域相同而子域不一样的例子,能够经过设置document.domain的办法来解决。
具体的作法是能够在http://www.a.com/a.html 和http://script.a.com/b.html 两个文件中分别设置document.domain = 'a.com',而后经过a.html文件中建立一个iframe,去控制iframe的contentDocument,这样两个js文件之间就能够“交互”了。
http://www.a.com/a.html页面

<iframe src="http://script.a.com/b.html" frameborder="0"></iframe>
<script>
    document.domain = 'a.com';
</script>

http://script.a.com/b.html页面

<script>
    document.domain = 'a.com';
</script>

这样俩个页面就能够经过js相互访问各类属性和对象了。

document.domain的设置是有限制的,咱们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com 中某个文档的document.domain 能够设成a.b.example.com、b.example.com 、example.com中的任意一个,可是不能够设成 c.a.b.example.com,由于这是当前域的子域,也不能够设成baidu.com,由于主域已经不相同了。


(五) HTML5的window.postMessage

window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可使用它来向其它的window对象发送消息,不管这个window对象是属于同源或不一样源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
window.postMessage容许两个窗口/帧之间跨域发送数据消息。从本质上讲,window.postMessage是一个跨域的无服务器垫片的Ajax。

用法:
otherWindow.postMessage(message, targetOrigin);

  • otherWindow: 对接收信息页面的window的引用。能够是页面中iframe的contentWindow属性;window.+open的返回值;经过name或下标从window.frames取到的值。
  • message: 所要发送的数据,string类型。
  • targetOrigin: 用于限制otherWindow,“*”表示不做限制

数据发送端
a.com/index.html中的代码:

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
    var ifr = document.getElementById('ifr');
    var targetOrigin = 'http://b.com';  // 设定接收端的域,*则为不限制
                                       
    ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

数据接收端
b.com/index.html中的代码:

<script type="text/javascript">
    window.addEventListener('message', function(event){
        // 经过origin属性判断消息来源地址
        if (event.origin == 'http://a.com') {
            alert(event.data);    // 弹出"I was there!"
            alert(event.source);  // 对a.com、index.html中window对象的引用
                                  // 但因为同源策略,这里event.source不能够访问window对象
        }
    }, false);
</script>

参考文章:JavaScript跨域总结与解决办法js中几种实用的跨域方法原理详解

脑细胞已经阵亡( ⊙ o ⊙ )

若是以为本文不错的话,帮忙点击下面的推荐哦

相关文章
相关标签/搜索