Cross Domain AJAX主要就是A.com網站的頁面發出一個XMLHttpRequest,這個Request的url是B.com,這樣的請求是被禁止的,瀏覽器處於安全考慮不允許進行跨域訪問,即同源策略。主要有4鍾方式解決。
1、跨域代理(Cross Domain Proxy)。
主要原理就是寫一個代理請求的轉發過程。客戶端請求自己的服務器,服務器把請求目標地址並且得到回應,服務器再把結果返回給客戶端。這種方式,對於開發者來說還是不錯的選擇,因為可以在服務器上對回應的結果做自己的處理后把重新組織過的數據返回給客戶端。
2、JSONP方式
JSONP的基本原理即是:利用HTML的<script>標簽可獲取任何來源JavaScript代碼的特點,實現數據的跨域訪問。在本地定義一個callback,通過<script>標簽的src屬性獲取遠程API的數據(將callback函數名傳遞過去),遠程服務器的API需要符合JSONP的規范,即將原本JSON格式的輸出數據改寫為javascript的函數調用代碼(callback為函數,原JSON數據為參數);這樣API返回的不再是JSON格式的數據而是JavaScript的代碼。
例子:
A.com/test.html的代碼如下:
- <html>
- <head>
- <script type="text/javascript">
- function callback(result) {
- alert(result.Name);
- }
- </script>
- <script type="text/javascript" src="http://B.com/api/user.php?cb=callback"></script>
- </head>
- <body>
- </body>
- </html>
將B.com/api/user.php
的代碼稍微進行修改,使得輸出結果為:
- callback({"Name": "Gavin", "Age" : 1982, "Rank": 7});
這樣當運行A.com/test.html的時候,代碼<script type="text/javascript" src="http://B.com/api/user.php?cb=callback"></script>的結果變為:
- <script type="text/javascript">
- callback({"Name": "Gavin", "Age" : 1982, "Rank": 7});
- </script>
然后調用本地定義的callback函數,輸出result.Name即為Gavin。最終實現跨域數據訪問。
3、使用Flash來跨域請求
在本地增加一個Flash文件,靠Flash文件來請求跨域的資源。詳見
4、 Cross-Origin Resource Sharing標准
通過定義一系列請求頭和響應頭,可以在客戶端透明(或者經過很少的修改)得支持跨源的 xmlhttprequest,那么只要 b.t.com 的響應設置合適的頭部信息,最好情況下 a.t.com 可以不經過任何修改就可以向 b.t.com 發請求.。這種方式有個問題,萬惡的IE瀏覽器要8以上才支持。這里
服務器通過返回響應頭進行權限控制,例如
Access-Control-Allow-Origin:控制那些外部請求可以訪問該資源
Access-Control-Allow-Credentials :結合客戶端 xmlhttprequest 的 withCredentials 屬性可以控制是否發送 cookie 等驗證信息
Access-Control-Allow-Headers :控制客戶端可以發送的額外頭部信息,多個值使用逗號分隔
Access-Control-Allow-Methods: 控制客戶端可以發送的請求方法(如:POST),多個值使用逗號分隔
ie 的例外
不出預料,ie 不完全支持此規范:
ie>=8
有自己的一套跨域請求機制 XDomainRequest ,通過替換 XmlHttpRequest 為XDomainRequest也可以往外部域發請求,但服務器端控制就少點,只能設置
Access-Control-Allow-Origin 控制那些外部請求可以訪問該資源
也就意味着:不能發送 cookie 信息, 不能設置額外請求頭。
子域訪問作為跨域訪問的特例,上述方法的任意一種都可行,但由於請求雙方間共享一個主域,因而存在另外一種方案
如:
a.t.com 希望發請求給 b.t.com 的資源地址,但 b.t.com 的資源實際上只能通過 b.t.com 下的請求才能訪問,而我們知道通過設置
- document.domain = "t.com" ;
那么 a.t.com 就可以操作 b.t.com 的文檔以及 window 對象。
問題
domain 設置是不可逆的,一旦主頁面設置了 domain,那么其包含的iframe除非設置和主頁面相同的 domain,否則就不能再和主頁面通信,會導致大量的已有代碼修改。