目錄:
1.同源策略
2.跨域
3.幾種跨域技術 - JSONP, CORS
1.同源策略
什么叫同源?
URL由協議、域名、端口和路徑組成,如果兩個URL的協議、域名和端口相同,則表示他們同源。相反,只要協議,域名,端口有任何一個的不同,就被當作是跨域。

e.g. 對於http://store.company.com/dir/page.html進行同源檢測:
URL | 結果 | 原因 |
---|---|---|
http://store.company.com/dir2/other.html |
成功 | 僅路徑不同 |
http://store.company.com/dir/inner/another.html |
成功 | 僅路徑不同 |
https://store.company.com/secure.html |
失敗 | 協議不同 |
http://store.company.com:81/dir/etc.html |
失敗 | 端口不同 |
http://news.company.com/dir/other.html |
失敗 | 主機名不同 |
瀏覽器采用同源策略,禁止頁面加載或執行與自身來源不同的域的任何腳本。換句話說瀏覽器禁止的是來自不同源的"document"或腳本,對當前"document"讀取或設置某些屬性。
情景:
比如一個惡意網站的頁面通過iframe嵌入了銀行的登錄頁面(二者不同源),如果沒有同源限制,惡意網頁上的javascript腳本就可以在用戶登錄銀行的時候獲取用戶名和密碼。
瀏覽器中有哪些不受同源限制呢?
<script>、<img>、<iframe>、<link>這些包含 src 屬性的標簽可以加載跨域資源。但瀏覽器限制了JavaScript的權限使其不能讀、寫加載的內容。
2.跨域
跨域是指從一個域的網頁去請求另一個域的資源。比如從http://www.baidu.com/ 頁面去請求 http://www.google.com 的資源。
3.跨域技術-JSONP
JSONP是什么?
上面提到過包含src屬性的<script>標簽可以加載跨域資源。 JSONP就是利用<script>標簽的跨域能力實現跨域數據的訪問。
JSONP實現的原理
在這之前,先來介紹下我是如何簡單的開啟服務的。
使用python的SimpleHTTPServer模塊(2.x)(3.x中時http.server)The
SimpleHTTPServer
module has been merged into http.server
in Python 3.0.
------------------------------------------------------------------------------------------------
如果你已經用過python,請跳過這里。
>>安裝python(注意設置環境變量 Path -- D:\Program Files\Python2.7.1;)
(驗證python安裝配置完成:打開cmd, 輸入python 有識別)
(cmd 切換工作目錄)
>>在工作目錄中執行
$ python -m SimpleHTTPServer 8088 (2.x)
$ python -m http.server 8088 (3.x)
>>服務啟動后,不要關閉該窗口;否則相當於殺死了該服務進程
------------------------------------------------我是分割線---------------------------------------
index.html,在8088端口提供服務

1 <!doctype html>
2 <html lang="en" ng-app="simpleApp">
3 <head>
4 <meta charset="UTF-8">
5 <script src="scripts/vendor/angular.min.js"></script>
6 <script src="scripts/vendor/angular-resource.min.js"></script>
7 <script src="scripts/controllers/controllers.js"></script>
8 <script src="scripts/services/services.js"></script>
9 <link href="styles/bootstrap.css" rel="stylesheet">
10
11 <!-- [跨域]step1. 通過擁有src屬性的標簽進行跨域調用 <script><img><iframe> -->
12 <script type="text/javascript" src="http://localhost:8090/remote.js"></script>
13
14 <!-- [跨域]step2. 本地函數被跨域的遠程js調用,並接收遠程js帶來的數據 -->
15 <script type="text/javascript">
16 var localHandler = function(data){ 17 alert('我是本地函數,可以被跨域的remote.js文件調用,遠程js帶來的數據是:' + data.result); 18 }; 19 </script>
20
21 <!-- [跨域]step3. JSONP client端的核心:實現動態查詢 22 怎么樣讓遠程JS知道它應該調用的本地函數叫什么名字? 23 client傳參告訴server"我想要一段調用xx函數的JS代碼,請返回給我";即client在發送請求URL時,指定回調函數-->
24 <script type="text/javascript">
25 // 得到航班信息查詢結果后的回調函數
26 var flightHandler = function(data){ 27 <!-- [跨域]step4. 處理server返回的數據:幾種格式 -->
28 /* JSONArray 29 * flightHandler([ 30 * {"code": "CA1998", "price": 1780, "tickets": 5 }, 31 * {"code": "CA2001", "price": 2090, "tickets": 10 } 32 * ]);*/
33 for(var i=0; i<data.length; i++){ 34 alert('你查詢的航班結果是:票價 ' + data[i].price + ' 元,' + '余票 ' + data[i].tickets + ' 張。'); 35 } 36
37 /* JSON 38 flightHandler({ "code": "CA1998", "price": 1780, "tickets": 5 }); 39 */
40 // alert('你查詢的航班結果是:票價 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 張。');
41 }; 42 // 提供jsonp服務的url地址(不管是什么類型的地址,最終生成的返回值都是一段javascript代碼)
43 var url = "http://localhost:8090/remote.js?code=CA1998&callback=flightHandler"; 44 // 創建script標簽,設置其屬性
45 var script = document.createElement('script'); 46 script.setAttribute('src', url); 47 // 把script標簽加入head,此時調用開始
48 document.getElementsByTagName('head')[0].appendChild(script); 49 </script>
50
51 <title>simpleApp</title>
52 </head>
53 <body>
54 <div ng-view></div>
55 </body>
56 </html>
remote.js,在8090端口提供服務,來模擬不同域的遠程文件(端口不同)

1 alert("遠程文件"); 2 localHandler({"result":"我是遠程js帶來的數據"}); 3
4 //JSON
5 flightHandler({ 6 "code": "CA1998", 7 "price": 1780, 8 "tickets": 5
9 }); 10
11 //JSONArray
12 flightHandler([{ 13 "code": "CA1998", 14 "price": 1780, 15 "tickets": 5
16 }, { 17 "code": "CA2001", 18 "price": 2090, 19 "tickets": 10
20 }]);
JSONP的缺點
JSONP只支持 GET 請求。
支持JSONP的不同技術
>>AngularJS
1 myUrl ="http://localhost:8090/api/test?callback=JSON_CALLBACK"; 2 $http.jsonp(myUrl).success( 3 function(data){ 4 alert(data); 5 } 6 );
1.angularJS中使用$http.jsonp函數
2.指定callback和回調函數名,函數名為JSON_CALLBACK時,會調用success回調函數,JSON_CALLBACK必須全為大寫。
3.也可以指定其它回調函數,但必須是定義在window下的全局函數。
4.url中必須加上callback
5.當callback為JSON_CALLBACK時,只會調用success,即使window中有JSON_CALLBACK函數,也不會調用該函數。
>>Ajax
1 myUrl ="http://localhost:8090/api/test"; 2 $.ajax({ 3 type:"GET", 4 url:myUrl, 5 dataType:"jsonp", 6 jsonp:"callback", 7 jsonpCallback:"jsonpCallback", 8 success:function(data){ 9 alert(data.msg); 10 } 11 }); 12 function jsonpCallback(data){ 13 alert(data); 14 }
JSONP 是通過動態添加<script>標簽來調用服務器的腳本(<script>含有src屬性,src屬性沒有跨域限制);而 Ajax 是通過 XHR(XmlHttpRequest) 對象。兩者並沒有直接關系,以上只是Ajax封裝JSONP的一種方式。
4.跨域技術-CORS (CrossOrigin Resources Sharing,跨源資源共享)
CORS是什么?
CORS,是 HTML5 的一項特性,它定義了一種瀏覽器和服務器交互的方式來確定是否允許跨域請求。
相對於 JSONP 這種解決方案來說,使用CORS,不需要要求服務器以指定格式返回數據(包裝成JS腳本的格式:callback_func({ data }););CORS,只需要在服務器端做一些通用設置。
enable cross-origin resource sharing 對各種服務器設置的詳細介紹,主流瀏覽器支持一覽。