標籤:developer test 因此 協議 with 方式 圖解 fun 函數名
1. 同源&跨域1.1 什麼是同源?什麼是跨域?
對比地址 |
是否同源 |
原因 |
http://api.example.com/detail.html |
不同源 |
網域名稱不同 |
https://www.example.com/detail.html |
不同源 |
協議不同 |
http://www.example.com:8080/detail.html |
不同源 |
連接埠不同 |
http://api.example.com:8080/detail.html |
不同源 |
網域名稱、連接埠不同 |
https://api.example.com/detail.html |
不同源 |
協議、網域名稱不同 |
https://www.example.com:8080/detail.html |
不同源 |
連接埠、協議不同 |
http://www.example.com/other.html |
同源 |
只是目錄不同 |
1.2 跨域的影響
- 如果要在
localhost/test.html
這個網站上訪問 http://api.douban.com/v2/movie/top250
這個介面,那麼瀏覽器會出現以下錯誤:
2. JSONP2.1 如何突破跨域要求節流2.1.1 使用img標籤(拿不到響應體)
我們知道:img
標籤,有個 href
屬性,這個屬性其實也是向伺服器發送請求,我們看看這種方式是否可以跨越訪問,代碼如下:
<img href="http://api.douban.com/v2/movie/top250" alt="">
此時可以看到能正確收到響應,但拿不到響應體(返回的JSON資料),
2.1.2 使用link標籤(拿不到響應體)
link
標籤,有個 src
屬性,我們以前是用來外聯css樣式,其實它也是相當於發送請求
<link rel="stylesheet" src="http://api.douban.com/v2/movie/top250"
看瀏覽器響應報文,可以發現link標籤也可以跨域請求,但是一樣,沒辦法拿到響應體
2.1.3 使用script標籤(曲線拿到響應體)
代碼如下:
1 <script>2 function test(json) {3 console.log(‘我被調用了‘);4 console.log(json);5 }6 </script>7 <script src="http://api.douban.com/v2/movie/top250?callback=test"></script>
結果如
說明:我們可以看到,我們預先定義了一個函數叫test,再然後在src裡加了一個參數callback=test,可以發現,當請求完成,會自動調用test這個函數,並且把響應體(JSON資料)當做參數傳遞過來
2.2 使用script標籤拿到JSON資料2.2.1 script匯入外部檔案作用
alert(‘你好‘);
<script src="1.txt"></script>
結果:
結論:script匯入檔案會預設把檔案內容當JS代碼執行,跟檔案格式無關
2.2.2 script標籤曲線拿到響應體原理
1 <script>2 //聲明一個success函數3 function success(obj){4 console.log(obj);5 }6 </script>7 <!-- script匯入檔案 -->8 <script src="http://www.demo.com/top250.php"></script>
echo "success(‘hello‘)";
結果
說明:請求的top250檔案裡,伺服器最終返回的是 success(‘hello‘); 這個當JS代碼執行時,是調用函數並傳遞參數hello的文法,因此可以看到success函數被調用,並且列印了參數hello
圖解:
★★ 思考:如果在上例中,把success函數的參數換成json對象,會怎樣?
1 $data = array(‘name‘ => ‘jack‘,‘age‘=>16,‘gender‘=>‘true‘ );2 3 $json = json_encode($data);4 5 echo "success({$json})";
- 再次訪問網頁可以發現,列印的參數就變成了json對象
結論:script標籤拿到JSON資料的原理就是在伺服器端寫呼叫瀏覽器端函數的方法 ,然後把JSON資料當參數傳遞過去
★★ 思考:現在服務端代碼這麼寫,如果要解決跨域問題,是不是每個瀏覽器端都要準備一個名叫success的函數?能讓瀏覽器端自己指定嗎?怎麼指定?
1 <script>2 //聲明函數3 function myFunc(obj){4 console.log(obj);5 }6 </script>7 8 <!-- 請求資料,並加入callback參數,值為myFunc -->9 <script src="http://www.demo.com/top250.php?callback=myFunc"></script>
- 此時,除了請求
top250.php
外,還傳遞了個 callback
的參數過去,修改 top250.php
,拿到這個參數
1 <?php 2 3 //拿到傳遞過來的參數,即函數名 4 $funcName = $_GET[‘callback‘]; 5 6 //準備資料 7 $data = array(‘name‘ => ‘jack‘,‘age‘=>16,‘gender‘=>true ); 8 9 //轉化為JSON10 $json = json_encode($data);11 12 //傳過來的是什麼函數名,就調用什麼函數13 echo "$funcName($json)"; 14 ?>
結果:此時就完成了指定函數名讓伺服器調用傳參的效果了。
這就是之前跨域拿資料的原理,即伺服器端呼叫瀏覽器端的函數,把參數傳遞過來即可
2.3 JSONP概念總結
JSONP:
它不是一套新技術,只是聰明的程式員想出的一套方案
能不能用這套方案,要看伺服器端代碼怎麼寫,伺服器端如果寫了調用函數的代碼,那麼就能支援JSONP方案
以後伺服器的介面會有介面文檔進行說明是否支援JSONP
建議:不要隨意使用別人的介面,特別是別人寫的支援JSONP的介面
例:https://developers.douban.com/wiki/?title=api_v2
3. CORS
// 允許遠端訪問header(‘Access-Control-Allow-Origin: *‘);
這種方案無需用戶端作出任何變化(用戶端不用改代碼),只是在服務端添加一個 Access-Control-Allow-Origin
的回應標頭,表示這個資源是否允許指定域請求(*代表任何網站都可以訪問)。
跨域&JSONP