同源策略產(chǎn)生和如何跨域請求

瀏覽器同源策略

含義

所謂同源策略,指的是瀏覽器對不同源的腳本或者文本的訪問方式進行的限制。比如源a的js不能讀取或設置引入的源b的元素屬性。
那么先定義下什么是同源,所謂同源,就是指兩個頁面具有相同的協(xié)議,主機(也常說域名),端口,三個要素缺一不可。

同源是指

* 協(xié)議相同
* 域名相同
* 端口相同

目的

同源策略的目的,是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。瀏覽器同時訪問2個跨域網(wǎng)站,如果A可以訪問B網(wǎng)站的信息,那么就數(shù)據(jù)隨時會被別人竊取。

限制范圍

隨著互聯(lián)網(wǎng)的發(fā)展,"同源政策"越來越嚴格。目前,如果非同源,共有三種行為受到限制。

* Cookie、LocalStorage和IndexDB無法讀取。
* DOM 無法獲取。
* AJAX 請求不能發(fā)送。

跨域的幾種解決方法

Cookie

Cookie 是服務器寫入瀏覽器的一小段信息,只有同源的網(wǎng)頁才能共享。但是,兩個網(wǎng)頁一級域名相同,只是二級域名不同,瀏覽器允許通過設置document.domain共享 Cookie。

舉例來說,A網(wǎng)頁是http://w1.example.com/a.html,B網(wǎng)頁是http://w2.example.com/b.html,那么只要設置相同的document.domain,兩個網(wǎng)頁就可以共享Cookie。

document.domain = 'example.com';

現(xiàn)在,A網(wǎng)頁通過腳本設置一個Cookie。

document.cookie = "test1=hello";

B網(wǎng)頁就可以讀到這個 Cookie。

var allCookie = document.cookie;

注意,這種方法只適用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 無法通過這種方法,規(guī)避同源政策,而要使用其他方法規(guī)避。

也可以通過后臺服務器端設置Cookie的時候,指定Cookie的所屬域名為一級域名,比如.example.com。

Set-Cookie: key=value; domain=.example.com; path=/

iframe

通過下面2個方法,去獲取不同源的iframe里面的DOM或者iframe里面獲取外面的DOM,都會跨域

document.getElementById("myIFrame").contentWindow.document
window.parent.document.body

解決方法和Cookie一樣,如果兩個窗口一級域名相同,只是二級域名不同,那么設置上一節(jié)介紹的document.domain屬性,就可以規(guī)避同源政策,拿到DOM。

這3種方法在這里就不過多描敘了,就是通過url的hash值和iframe里面通信

* 片段識別符(fragment identifier)
* window.name
* 跨文檔通信API(Cross-document messaging)

JSONP

它的基本思想是,網(wǎng)頁通過添加一個<script>元素,向服務器請求JSON數(shù)據(jù),這種做法不受同源政策限制;服務器收到請求后,將數(shù)據(jù)放在一個指定名字的回調(diào)函數(shù)里傳回來。

首先,網(wǎng)頁動態(tài)插入<script>元素,由它向跨源網(wǎng)址發(fā)出請求。

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

上面代碼通過動態(tài)添加<script>元素,向服務器example.com發(fā)出請求。注意,該請求的查詢字符串有一個callback參數(shù),用來指定回調(diào)函數(shù)的名字,這對于JSOPNP是必需的。

服務器收到這個請求以后,會將數(shù)據(jù)放在回調(diào)函數(shù)的參數(shù)位置返回。

foo({
  "ip": "8.8.8.8"
});

由于<script>元素請求的腳本,直接作為代碼運行。這時,只要瀏覽器定義了foo函數(shù),該函數(shù)就會立即調(diào)用。作為參數(shù)的JSON數(shù)據(jù)被視為JavaScript對象,而不是字符串,因此避免了使用JSON.parse的步驟。

WebSocket

WebSocket是一種通信協(xié)議,使用ws://(非加密)和wss://(加密)作為協(xié)議前綴。該協(xié)議不實行同源政策,只要服務器支持,就可以通過它進行跨源通信。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容