同源策略與跨域資源共享的糾纏

導語
你家的小孩帶了他的朋友來大家的家裏玩,你家的小孩若是要在自家屋裏拿玩具玩、拿東西吃你天然是不會阻止,可是若是你家小孩的朋友人品不行,亂拿東西吃、亂翻你家的東西,你天然不容許,拿什麼東西要經過你的容許才行。php

扯了這麼多,天然不是爲了吹水,而是要爲了引出前端開發的一個重要的知識點——同源策略html

什麼是同源策略

出於保護用戶信息安全的目的,如今的瀏覽器都會實施「同源策略」這個政策,所謂「同源策略」指的是不一樣源的客戶端腳本在沒有明確受權狀況下,不容許讀寫對方的資源。前端

試想,若是你在淘寶購物完後,帶着淘寶的登錄信息又去京東,保不許京東把你給黑掉,okay這只是開個玩笑~~~ajax

可是,在不少狀況下咱們又常常須要跨域訪問資源,好比你要在我的博客上建立一個音樂播放器,但這個接口若是本身建立的話性價比過低了,這就須要其餘源提供一個可訪問的接口給你使用,這裏就涉及到突破同源策略的限制的跨域訪問json

所謂同源:跨域

  • 同協議:如都是http瀏覽器

  • 同域名:如都是terenyeung.applinzi.com/newapp/carousel.html和terenyeung.applinzi.com/index.html安全

  • 同端口:如都是80端口服務器

什麼是跨域

而所謂的跨域,指的是突破同源策略的限制,本源的客戶端腳本訪問其餘源的數據app

跨域的實現方式

目前,實現跨域訪問的方法包括:

- JSONP
- Cross-Origin Resource Sharing
- HTML5 postMessage
- 其餘Hack
  - 利用hash
  -  利用window.name

這裏主要講解經常使用的JSONP和CORS兩種跨域方法。

  • JSONP

    JSONP的全稱是JSON with Padding,

原理
- JSONP是經過script標籤加載數據的方式去獲取其餘源的數據,而後當作js代碼來執行;

- 你須要提早在文檔中聲明一個回調函數,該函數的函數名經過GET的方式向後臺傳參,後臺解析到函數名後在原始數據上padding這個函數名,而後在發給前端,最終這個返回前端的字符串將做爲js的一部分執行
範例解析:
//你如今所在的頁面是
http://terenyeung.applinzi.com/newapp/task31/jsonp.html
//你如今的需求是想要獲取另外一個源http://teren.applinzi.com/jsonp.php的數據

//利用jsonp實現跨域訪問的具體作法是:
//1.在該頁面添加一個script標籤,當加載script的時候就會向另外一個源(http://teren.applinzi.com/task31/jsonp.php)發送GET的請求;
//2.存放在另外一個源的後臺腳本對前端發過來的查詢字符串(帶函數名)進行判斷,若是存在則爲後臺返回的數據包裹上帶有該函數名的字符串,即
if($callback){    
  echo $callback.'('.json_encode($data).')';
}else{    
  echo $data;
}


<script>     
/* function $(id){          
return document.querySelector(id)      }*/     
var btn = document.getElementsByClassName('btn')[0];     
//點擊按鈕時實時建立一個script標籤      
btn.addEventListener('click',function(){          
var script = document.createElement('script');          
script.src = 'http://teren.applinzi.com/task31/jsonp.php?callback=appendHtml';          
document.body.appendChild(script);          
document.body.removeChild(script);      
})    
function appendHtml(news){        
 var html='';       
 for (var i=0 ; i<news.length ; i++){            
  html += '<li>'+news[i]+'</li>';            
  console.log(news[i]);        
}        
document.getElementsByClassName('box')[0].innerHTML = html    }
</script>
<?php   
header("Content-type: ");   
$callback = $_GET['callback'];   
$news = array("第11日前瞻:中國衝擊4金 博爾特再戰200米羽球","正直播柴飈/洪煒出戰 男雙力爭會師決賽","女排將死磕巴西!郎平安排男陪練模仿對方核心","沒有中國選手和巨星的110米欄 咱們還看嗎?", "中英上演奧運金牌大戰","博彩賠率挺中國奪回第二紐約時報:中國因對手服禁藥而丟失的獎牌最多","最「出櫃」奧運?同性之愛閃耀里約","下跪拜謝與洪荒之力同樣 都是真情流露");   
$data = array();   
for ($i=0;$i<3;$i++){        
$idx = intval(rand(0,7));        
array_push($data,$news[$idx]);        
array_splice($news,$idx,1);   
};  
 if($callback){       
echo $callback.'('.json_encode($data).')';  
 }else{       
echo $data;   }
?>
代碼

跨域實現方式——JSONP

  • CORS

CORS的全稱是Cross-Origin Resources Sharing,它容許瀏覽器向跨源服務器,發出請求,從而克服了AJAX只能同源使用的限制

原理
  • CORS須要瀏覽器和服務器同時支持。目前,全部瀏覽器都支持該功能,IE瀏覽器不能低於IE10;

  • 瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息——origin字段,告訴跨域的後臺此次跨域請求是由哪一個源(這裏是http://terenyeung.applinzi.com
    發出的

  • 實現CORS通訊的關鍵是服務器。只要服務器實現了CORS接口,就能夠跨源通訊。服務器根據前端發過來的跨域的ajax請求的origin字段,決定是否贊成此次的跨域訪問;
    若是後臺贊成的話,能夠在後臺文檔(以php後臺爲例)中設置以下:

添加一個頭:
<? 
header('Access-Control-Allow-Origin: *');
//header('Access-Control-Allow-Origin: http://terenyeung.applinzi.com');
?>
[注]*爲容許全部的源訪問

若是被容許另外一個源跨域訪問,則返回的頭信息必定包含以下字段:
Access-Control-Allow-Origin: http://terenyeung.applinzi.com
或者
Access-Control-Allow-Origin: *
範例解析
<?php   
header("Content-type: ");    
header('Access-Control-Allow-Origin: *');   
$news = array("第11日前瞻:中國衝擊4金 博爾特再戰200米羽球","正直播柴飈/洪煒出戰 男雙力爭會師決賽","女排將死磕巴西!郎平安排男陪練模仿對方核心","沒有中國選手和巨星的110米欄 咱們還看嗎?", "中英上演奧運金牌大戰","博彩賠率挺中國奪回第二紐約時報:中國因對手服禁藥而丟失的獎牌最多","最「出櫃」奧運?同性之愛閃耀里約","下跪拜謝與洪荒之力同樣 都是真情流露");   
$data = array();  
 for ($i=0;$i<3;$i++){        
   $idx = intval(rand(0,7));        
   array_push($data,$news[$idx]);        
   array_splice($news,$idx,1);  
 };   
 echo json_encode($data)   
// header('Access-Control-Allow-Origin: http://terenyeung.applinzi.com/task31/CORS.html');
?>
代碼

跨域實現方式——CORS

參考資料

阮一峯——瀏覽器同源政策及其規避方法
阮一峯——跨域資源共享 CORS 詳解
知乎——「每日一題」JSONP 是什麼?
飢人谷——同源策略及跨域資源共享

相關文章
相關標籤/搜索