JavaScript中的跨域详解(内附源码)

什么是跨域?

什么是跨域?

所谓跨域,就是如果在不同的域名下面存在数据交互,这个时候就会存在跨域的问题,这里要说明的是在同一个网站不同的文件夹下的数据交互是不存在跨域问题的。

哪些情况下存在跨域问题?

  • 主域和子域之间会存在跨域问题(比如 www.a.comwww.a.b.com)。

  • 不同的域名存在跨域问题,哪怕这两个域名指向的是同一个ip地址。


为什么 ajax 不可以跨域?

因为 ajax 是通过 XMLHttpRequest 这个对象来进行数据之间的交互的,而 XMLHttpRequest 为了安全起见是不允许跨域交互数据,所以 ajax 是不可以跨域的。


跨域问题的几种解决方式?

jsonp

原理:动态插入 script 标签,通过 script 标签引入一个js文件,这个js文件载入成功后会执行我们在 url 参数中指定的函数,并且会把我们需要的 json数据作为参数传入。

由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出 JSON 数据并执行回调函数,从而解决了跨域的数据请求。

优点是兼容性好,简单易用,支持浏览器与服务器双向通信。缺点是只支持GET请求。

JSONP:json+padding(内填充),顾名思义,就是把JSON填充到一个盒子里

jsonp有一个缺点就是只能单域操作,就是我们不可以通过本网站去修改其他网站的数据。

使用 jsonp 来进行跨域是平时比较常用的,用 script 标签的形式,script 标签不存在跨域的问题,(不仅如此,我们还发现凡是拥有“src”这个属性的标签都拥有跨域的能力,比如<script><img><iframe>)我们也把它统称为 jsonp 的形式。

我们可以把 script 里面的 src 当做请求的地址,你要知道 script 标签不是仅仅只能请求 js文件,比如说它还可以请求 php。只要是这个页面运算完返回的结果是 json 或者是 js 它就不会有问题。

实例一:

</head>
<body>
<script type="text/javascript">
    //a.com
</script>

<!-- 假如我们这里引入的是b网站的php文件, a网站的数据就可以通
过 src 传送到 b 网站,a 网站的数据是加到问号后面的,然后数据
在 b 网站进行运算,最终把返回的结果输出出来,那我们在 a 网站中
就可以调用到b网站的数据了-->

<script type="text/javascript" src="b.php?key=value&key2=value2"></script>
</body>

实例二:

(jsonp.html)

<body>
<script type="text/javascript">

    //a.com
    //注意这里名字要一样,即 box
    function box(json){

    //这个时候在 a 网站下我们就可以取到这个 name 值了
        alert(json.name);
    }
</script>

<script type="text/javascript" src="1.jsonp.js"></script>
</body>
(jsonp.js)

//b.com
//我把数据写到盒子里面之后,我这个数据是在 b 网站的地址下面
//的,而我们要调用的时候就可以利用回调的原理进行调用。

box({name : 'laowang'});

效果展示 || 源代码

动态创建 jsonp

(jsonp.html)

<script type="text/javascript">

    function createJs(sUrl){
        var oScript = document.createElement('script');
        oScript.type = 'text/javascript';
        oScript.src = sUrl;
        document.getElementsByTagName('head')[0].appendChild(oScript);
    }

    createJs('jsonp.js?callbcak=box');

    //这个 box 必须和 jsonp 中的 box 一致,但是有的时候,
    //你不知道这个名字是什么,那我们就可以自己写一个参数加进去
    //从而让自己来来控制这个名字 
    //即:?callbcak=box

    function box(json){
        alert(json.name);
    }
</script>
(jsonp.js)

box({name : 'laowang'});

效果展示 || 源代码

当然,jquery 中也提供了封装好的 jsonp 方法。最后再提一句,一般不会选择在页面上直接引入 <script> 这种方式,而是在 js 中动态生成 <script> 节点。

CORS

即使浏览器对 CORS 的支持程度并不都一样,但所有浏览器都支持简单的(非 Perflight 和 不带凭据的)请求,因此有必要实现一个跨浏览器的方案。检测 XHR 是否支持 CORS 的最简单的方式,就是检查是否存在 withCredentials 属性。在结合检测 XDomainRequest 对象是否存在,就可以兼顾所有的浏览器了。

具体代码如下:

function createCORSRequest(method,url){
    var xhr = new XMLHttpRequest();
    if("withCredentials" in xhr){
        xhr.open(method,url,true);
    } else if(typeof XDomainRequest != "undefined"){
        xhr = new XDomainRequest();
        xhr.open(method,url);
    } else {
        xhr = null;
    }
    return xhr;
}

//由于无论是同源请求还是跨域请求都是用相同的接口,因此对于本地
//资源,最好使用相对rul,再访问远程资源时在使用绝对url。
var request = createCORSRequest(method,url);

if(request){
    request.onload = function(){
        //对 request.responseText 进行处理
    };
    request.send();
}

createCORSRequest() 返回的对象中,在所有的浏览器中都可以使用下列方法或者属性:

abort() : 用于停止正在进行的请求
onerror : 用于代替 onreadystatechange 检测错误
onload : 用于代替 onreadystatechange 检测成功
responseText : 用于取得相应内容
send() : 用于发送请求

location.hash

可以利用 location.hash 值进行跨域,因为我们跨域无非就是发送一个请求,然后取得页面的数据。我们可以通过 iframe 利用 location.hash 来进行跨域操作。这个方法的优点就是可以进行双域操作。

原理:比如说我在 a 网站上嵌套了一个 b 网站的 iframe 这个时候,我们就可以把数据添加到用 script 标签引入的 php 的哈希值上,即 src="xxx.php#key1=value&amp;key2=value2",哈希值加完之后不会改变页面的网址,这样可以把数据带到 b 网站,然后 b 网站就可以根据数据进行解析,返回数据,然后a 网站可以通过 parent.location.hash 来更新本页面的 hash 值,那这个时候 a 网站就可以获取到 b 网站上的数据了。

但是这个方法是另一个域下面的,为了安全起见,有的浏览器是不支持的,比如说 iechrome,咱们没办法直接从另一个域上面找到它的父级,这样的话咱们就可以通过在 a 网站的页面当中再去创建一个 a 网站的页面。

比如说创建一个新的页面 yyy.html,他也是 a网站的,然后把数据添加到 a 网站的 yyy.html 这个页面中,添加号之后呢,这个时候我们就可以在 a 网站通过这个方法 parent.location.hash = self.location.hash获取数据, 因为他们现在是同一个域下面的,这样子就可以通过改变hash 值,来进行这两个域之间的数据交互。

window.name

还可以用 window.name 来解决跨域的问题,这个是比较安全的,因为内容写到了 window.name 上,不会暴露出来。

window 对象有个 name 属性,该属性有个特征:即在一个窗口 (window) 的生命周期内,窗口载入的所有的页面都是共享一个 window.name 的,每个页面对 window.name 都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的。

原理:现在有两个网站,这两个网站下面各有一个页面 www.a.com -->a1.html 和 www.b.com -->b1.html,然后我们也是通过在 a 网站的 a1.html 下面创建一个 iframe标签,然后 src 指定的就是 b 网站数据的 b1 这个页面,然后我们在 b 网站的 b1.html window.name = '数据';下面去写数据就可以了。

写完之后,当 a1 加载完之后,我们在 b1 下面去创建 a1 的一个代理文件,www.b.com --> agent.html,创建完之后,代理文件和 window.name 是共用数据的,这个时候当我再请求 a1.html 的时候,就可以通过代理来取到数据了。

这个和 hash 的原理其实是差不多的,都是在自己的域下面创建一个当前要用数据那个域的一个代理文件,然后再通过代理和当前文件在同一个域下的一个原则,然后把数据提交过去。

个人认为 window.name 的方法既不复杂,也能兼容到几乎所有浏览器,这真是极好的一种跨域方法。

document.domain

在子域和主域之间都设置 document.domain = '主域名的网址';

将子域和主域的 document.domain 设为同一个主域。前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域。

服务器代理

不同的域名下通过服务器代理解决:服务器代理是通过在服务器下面做这个对象XMLHttpRequest 的代理文件,然后服务器去做运算,他的优点是你可以做到任何你想要的数据交互,而它的缺点是会增大服务器的压力。

flash

flash也可以解决跨域的问题。

postMessage

postMessagehtml5的方法,有兴趣的同学可以自己去看一下。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值