跨域的概念
跨域你們都知道,不一樣地址,不一樣端口,不一樣級別,不一樣協議都會構成跨域。例如: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>