同源和跨域詳解


同源

同源策略的基本概念

1995年,同源政策由 Netscape 公司引入瀏覽器。目前,所有瀏覽器都實行這個政策。同源策略:最初,它的含義是指,A網頁設置的 Cookie,B網頁不能打開,除非這兩個網頁"同源"。所謂"同源"指的是"三個相同"。


協議相同
域名相同
端口相同

舉例來說,這個網址http://www.example.com/dir/page.html協議是http://

域名是www.example.com,端口是80(默認端口可以省略)。它的同源情況如下。


http://www.example.com/dir2/other.html:同源

file:///F:/phpStudy/WWW/day01/04-demo/04.html 不同源(協議不同)
http://v2.www.example.com/dir/other.html:不同源(域名不同)
http://www.example.com:81/dir/other.html:不同源(端口不同)

同源策略的目的

同源政策的目的,是為了保證用戶信息的安全,防止惡意的網站竊取數據。

同源策略的限制范圍

隨着互聯網的發展,“同源策略”越來越嚴格,目前,如果非同源,以下三種行為都將收到限制。


1. Cookie、LocalStorage IndexDB 無法讀取。
2. DOM 無法獲得。
3. AJAX 請求在瀏覽器端有跨域限制

雖然這些限制是很有必要的,但是也給我們日常開發帶來不好的影響。比如實際開發過程中,往往都會把服務器端架設到一台甚至是一個集群的服務器中,把客戶端頁面放到另外一個單獨的服務器。那么這時候就會出現不同源的情況,如果我們知道兩個網站都是安全的話,我們是希望兩個不同源的網站之間可以相互請求數據的。這就需要使用到跨域 。

跨域

jsonp( 無兼容性問題 )

JSONP(JSON with Padding)、可用於解決主流瀏覽器的跨域數據訪問的問題。

原理:服務端返回一個定義好的js函數的調用,並且將服務器的數據以該函數參數的形式傳遞過來,這個方法需要前后端配合

script 標簽是不受同源策略的限制的,它可以載入任意地方的 JavaScript 文件。類似的還有imglink標簽


<!--不受同源策略限制的標簽-->
<img src="http://www.api.com/1.jpg" alt="">
<link rel="stylesheet" href="http://www.api.com/1.css">
<script src="http://www.api.com/1.js"></script>

 

jsonp演化過程1

php文件


header("content-type:text/html;charset=utf-8");
echo "alert(1111)";

html文件


<script src="http://www.api.com/testjs.php"></script>

原理:其實src的路徑是什么文件不重要,無論引入js文件還是php文件,最后返回給瀏覽器的都是字符串,因此我們script標簽是可以引入一個php文件的。

 

jsonp演化過程2

php文件


header("content-type:text/html;charset=utf-8");
echo "var a = 118;";

html文件


<script src="http://www.api.com/testjs.php"></script>
<script>
 //a打印出來了118
 console.log(a);
</script>

我們現在做到了一件事情,從不同源的php文件中獲取到了數據

 

缺點:獲取數據的script標簽必須寫在使用的script標簽的前面,必須保證先有數據才能對數據進行渲染。

 

jsonp演化過程3

php代碼


header("content-type:text/html;charset=utf-8");
$arr = array(
   "name"=>"zs",
   "age"=>18
);
$result = json_encode($arr);
//這是一段js函數的調用的代碼,$result就是我們想要的數據
echo "func($result)";

js代碼


<script>
 function func(data) {
   console.log(data);
}
</script>
<script src="http://www.api.com/testjs.php"></script>

 

缺點:后端必須知道前端聲明的方法的名字,后端才能調用。

 

jsonp演化過程4

php代碼


header("content-type:text/html;charset=utf-8");
$arr = array(
   "name"=>"zs",
   "age"=>18
);
$result = json_encode($arr);
//這是一段js函數的調用的代碼,$result就是我們想要的數據
echo $_GET['callback']."($result)";

javascript代碼


function fun(data) {
 console.log(data);
}
var button = document.querySelector("button");
button.onclick = function () {
 var script = document.createElement("script");
 script.src = "http://www.api.com/testjs.php?callback=fun";
 document.body.appendChild(script);
}

 

  1. 說白了,jsonp的原理就是 借助了script標簽 src 請求資源時, 不受同源策略的限制.

  2. 在服務端返回一個函數的調用,將數據當前調用函數的實參。

  3. 在瀏覽器端,需要程序要聲明一個全局函數,通過形參就可以獲取到服務端返回的對應的值

 

jsonp原理大家需要知道,但不用太過於去糾結這個原理,因為jquery已經幫我們封裝好了,我們使用起來非常的方便。

jquery對於jsonp的封裝


//使用起來相當的簡單,跟普通的get請求沒有任何的區別,只需要把dataType固定成jsonp即可。
$.ajax({
 type:"get",
 url:"http://www.Jepson.com/testjs.php",
 dataType:"jsonp",
 data:{
   uname:"Jepson",
   upass:"123456"
},
 success:function (info) {
   console.log(info);
}
});

XMLHttpRequest2.0

XMLHttpRequest是一個javascript內置對象,使得Javascript可以進行異步的HTTP通信。2008年2月,就提出了XMLHttpRequest Level 2 草案。

老版本的XMLHttpRequest的缺點:


1. 僅支持傳輸文本數據,無法傳說二進制文件,比如圖片視頻等。
2. 傳輸數據時,沒有進度信息,只能提示完成與否。
3. 受到了"同源策略"的限制

 

新版本的功能:


1. 可以設置timeout超時時間
2. 可以使用formData對象管理表單數據
3. 允許請求不同域名下的數據(跨域)
4. 支持上傳二進制文件
5. 可以獲取數據傳輸的進度信息

timeout設置超時


xhr.timeout = 3000;//設置超時時間
xhr.ontimeout = function(){
 alert("請求超時");
}

formData管理表單數據

formData對象類似於jquery的serialize方法,用於管理表單數據


使用特點:
1. 實例化一個formData對象, new formData(form); form就是表單元素
2. formData對象可以直接作為 xhr.send(formData)的參數。注意此時數據是以二進制的形式進行傳輸。
3. formData有一個append方法,可以添加參數。formData.append("id", "1111");
4. 這種方式只能以post形式傳遞,不需要設置請求頭,瀏覽器會自動為我們設置一個合適的請求頭。

 

代碼示例:


//1. 使用formData必須發送post請求
   xhr.open("post", "02-formData.php");
   
//2. 獲取表單元素
var form = document.querySelector("#myForm");
//3. 創建form對象,可以直接作為send的參數。
var formData = new FormData(form);

//4. formData可以使用append方法添加參數
formData.append("id", "1111");

//5. 發送,不需要指定請求頭,瀏覽器會自動選擇合適的請求頭
xhr.send(formData);

 

文件上傳

以前,文件上傳需要借助表單進行上傳,但是表單上傳是同步的,也就是說文件上傳時,頁面需要提交和刷新,用戶體驗不友好,xhr2.0中的formData對象支持文件的異步上傳。


var formData = new FormData();
//獲取上傳的文件,傳遞到后端
var file = document.getElementById("file").files[0];
formData.append("file", file);
xhr.send(formData);

 

顯示文件進度信息

xhr2.0還支持獲取上傳文件的進度信息,因此我們可以根據進度信息可以實時的顯示文件的上傳進度。


1. 需要注冊 xhr.upload.onprogress = function(e){} 事件,用於監聽文件上傳的進度.注意:需要在send之前注冊。
2. 上傳的進度信息會存儲事件對象e中
3. e.loaded表示已上傳的大小   e.total表示整個文件的大小

 

代碼參考:


xhr.upload.onprogress = function (e) {
 
 inner.style.width = (e.loaded/e.total*100).toFixed(2)+"%";
 span.innerHTML = (e.loaded/e.total*100).toFixed(2)+"%";
}

xhr.send(formData);

如果上傳文件超過8M,php會報錯,需要進行設置,允許php上傳大文件。

 

跨域資源共享(CORS) ( 兼容性IE10+ )

cors的使用

新版本的XMLHttpRequest對象,可以向不同域名的服務器發出HTTP請求。這叫做"跨域資源共享"(Cross-origin resource sharing,簡稱CORS)。

跨域資源共享(CORS)的前提

  • 瀏覽器支持這個功能( 兼容性IE10+ )

  • 服務器必須允許這種跨域。

服務器允許跨域的代碼:


//允許所有的域名訪問這個接口
header("Access-Control-Allow-Origin:*");
//允許www.study.com這個域名訪問這個接口
header("Access-Control-Allow-Origin:http://www.study.com");

 

CORS的具體流程(了解)

  1. 瀏覽器發送跨域請求

  2. 服務器端收到一個跨域請求后,在響應頭中添加Access-Control-Allow-Origin Header資源權限配置。發送響應

  3. 瀏覽器收到響應后,查看是否設置了header('Access-Control-Allow-Origin:請求源域名或者*');

    如果當前域已經得到授權,則將結果返回給JavaScript。否則瀏覽器忽略此次響應。

結論:

  1. 跨域行為是瀏覽器行為,響應是回來了的, 只是瀏覽器安全機制做了限制, 對於跨域響應內容進行了忽略。

  2. 服務器與服務器之間是不存在跨域的問題的

 

jsonp與cors的對比

  • jsonp兼容性好,老版本瀏覽器也支持,但是jsonp僅支持get請求,發送的數據量有限。使用麻煩

  • cors需要瀏覽器支持cors功能才行。但是使用簡單,只要服務端設置允許跨域,對於客戶端來說,跟普通的get、post請求並沒有什么區別。

  • 跨域的安全性問題:因為跨域是需要服務端配合控制的 ,也就是說不論jsonp還是cors,如果沒有服務端的允許,瀏覽器是沒法做到跨域的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM