跨域的概念
跨域你们都知道,不一样地址,不一样端口,不一样级别,不一样协议都会构成跨域。例如:about.haorooms.com和www.haorooms.com都会构成跨域。总结起来只要协议、域名、端口有任何一个不一样,都被看成是不一样的域。下面举例,每两个一组。javascript
URL 说明 是否容许通讯 http://www.haorooms.com/a.js http://www.haorooms.com/b.js 同一域名下 容许 http://www.haorooms.com/lab/a.js http://www.haorooms.com/script/b.js 同一域名下不一样文件夹 容许 http://www.haorooms.com:8000/a.js http://www.haorooms.com/b.js 同一域名,不一样端口 不容许 http://www.haorooms.com/a.js https://www.haorooms.com/b.js 同一域名,不一样协议 不容许
http://www.haorooms.com/a.js http://60.32.92.74/b.js 域名和域名对应ip 不容许 http://www.haorooms.com/a.js http://about.haorooms.com/b.js 主域相同,子域不一样 不容许 http://www.haorooms.com/a.js http://haorooms.com/b.js 同一域名,不一样二级域名(同上) 不容许(cookie这种状况下也不容许访问) http://www.hao123.com/a.js http://www.haorooms.com/b.js 不一样域名 不容许
解决跨域的方案
上一篇文章,我写了window.postMessage,是一种跨域的解决方案。今天再介绍几个。php
CORS跨域资源共享
众所周知,咱们以前跨域不少时候用的是jsonp的方式,jsonp的方式我后面介绍。下面说说CORS跨域和jsonp跨域的优点:html
CORS与JSONP相比,无疑更为先进、方便和可靠。前端
一、 JSONP只能实现GET请求,而CORS支持全部类型的HTTP请求。java
二、 使用CORS,开发者可使用普通的XMLHttpRequest发起请求和得到数据,比起JSONP有更好的错误处理。jquery
三、 JSONP主要被老的浏览器支持,它们每每不支持CORS,而绝大多数现代浏览器都已经支持了CORS。[低版本IE7如下不支持,要支持IE7仍是要用jsonp方式]ajax
CORS的使用json
CORS要先后端同时作配置。后端
一、首先咱们来看前端。跨域
纯js的ajax请求。
<script type="text/javascript"> var xhr = new XMLHttpRequest(); //ie6如下用new ActiveXObject("Microsoft.XMLHTTP");能够作能力判断。 xhr.open("GET", "/haorooms",true); xhr.send(); </script>
以上的haorooms是相对路径,若是咱们要使用CORS,相关Ajax代码可能以下所示:
<script type="text/javascript"> var xhr = new XMLHttpRequest();//ie6如下用new ActiveXObject("Microsoft.XMLHTTP");能够作能力判断。 xhr.open("GET", "http://www.haorooms.com/CORS",true); xhr.send(); </script>
固然,你也能够用jquery的ajax进行。
二、后端或者服务器端的配置
下面咱们主要介绍Apache和PHP里的设置方法。
Apache:Apache须要使用mod_headers模块来激活HTTP头的设置,它默认是激活的。你只须要在Apache配置文件的 < Directory >, < Location>, < Files >或< VirtualHost>的配置里加入如下内容便可:
Header set Access-Control-Allow-Origin *
PHP:只须要使用以下的代码设置便可。
<?php header("Access-Control-Allow-Origin:*");
以上的配置的含义是容许任何域发起的请求均可以获取当前服务器的数据。固然,这样有很大的危险性,恶意站点可能经过XSS攻击咱们的服务器。因此咱们应该尽可能有针对性的对限制安全的来源,例以下面的设置使得只有www.haorooms.com这个域才能跨域访问服务器的API。
Access-Control-Allow-Origin: http://www.haorooms.com
经过jsonp跨域
jsonp跨域也须要先后端配合使用。通常后端设置callback ,前端给后台接口中传一个callback 就能够。
例如前端代码:
<script type="text/javascript"> function dosomething(jsondata){ //处理得到的json数据 } </script> <script src="http://haorooms.com/data.php?callback=dosomething"></script>
后台代码:
<?php $callback = $_GET['callback'];//获得回调函数名 $data = array('a','b','c');//要返回的数据 echo $callback.'('.json_encode($data).')';//输出 ?>
假如你用ajax方式进行jsonp跨域,我以前的一篇文章中说起过:http://www.haorooms.com/post/jquery_ajax_wg
/* //简写形式,效果相同 $.getJSON("url跨域地址", {参数,要把callback做为参数传到后端}, function(data){ //结构处理 },"jsonp"); */ $.ajax({ type : "get", url : "跨域地址", dataType : "jsonp",//数据类型为jsonp jsonp: "callback",//服务端用于接收callback调用的function名的参数【后台接受什么参数,咱们就传什么参数】咱们上面设置是callback success : function(data){ //结果处理 }, error:function(data){ console.log(data); } });
经过修改document.domain来跨子域
咱们只须要在跨域的两个页面中设置document.domain就能够了。修改document.domain的方法只适用于不一样子域的框架间的交互。
例如:1.在页面 http:// www.haorooms.com/a.html 中设置document.domain
<iframe id = "iframe" src="http://haorooms.com/b.html" onload = "test()"></iframe> <script type="text/javascript"> document.domain = 'haorooms.com';//设置成主域 function test(){ alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象 } </script>
二、在页面http:// haorooms.com/b.html 中设置document.domain
<script type="text/javascript"> document.domain = 'haorooms.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同 </script>
使用window.name来进行跨域
原理:
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的全部的页面都是共享一个window.name的,每一个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的全部页面中的。
方法:
假若有三个页面。
a.com/app.html:应用页面。 a.com/proxy.html:代理文件,通常是一个没有任何内容的html文件,须要和应用页面在同一域下。 b.com/data.html:应用页面须要获取数据的页面,可称为数据页面。
一、在应用页面(a.com/app.html)中建立一个iframe,把其src指向数据页面(b.com/data.html)。
数据页面会把数据附加到这个iframe的window.name上,data.html代码以下:
<script type="text/javascript"> window.name = 'I was there!'; // 这里是要传输的数据,大小通常为2M,IE和firefox下能够大至32M左右 // 数据格式能够自定义,如json、字符串 </script>
二、在应用页面(a.com/app.html)中监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理文件(代理文件和应用页面在同一域下,因此能够相互通讯)。
app.html部分代码以下:
<script type="text/javascript"> var state = 0, iframe = document.createElement('iframe'), loadfn = function() { if (state === 1) { var data = iframe.contentWindow.name; // 读取数据 alert(data); //弹出'I was there!' } else if (state === 0) { state = 1; iframe.contentWindow.location = "http://a.com/proxy.html"; // 设置的代理文件 } }; iframe.src = 'http://b.com/data.html'; if (iframe.attachEvent) { iframe.attachEvent('onload', loadfn); } else { iframe.onload = loadfn; } document.body.appendChild(iframe); </script>
三、获取数据之后销毁这个iframe,释放内存;这也保证了安全(不被其余域frame js访问)。
<script type="text/javascript"> iframe.contentWindow.document.write(''); iframe.contentWindow.close(); document.body.removeChild(iframe); </script>