當前位置:
首頁 > 最新 > 瀏覽器同源策略及 Ajax 跨域解決方案

瀏覽器同源策略及 Ajax 跨域解決方案

想法丨發現丨習慣

同道者同行 同行者同享

因為在開發過程中會經常遇到因為瀏覽器同源策略而導致的跨域問題,而多數開發者對瀏覽器同源策略和跨域問題並沒有很清晰的認識,所以打算在這篇文章中說下瀏覽器同源策略和我們最經常會遇到的 Ajax 跨域問題及其解決方案。

對於源的定義,MDN 中是這麼解釋的:如果兩個頁面的協議、域名和埠都相同,則兩個頁面具有相同的源。

從定義我們可以知道,關注兩個頁面是否同源,只要比較兩個頁面的協議域名即可。

舉個例子,假設有以下頁面,比較 A 頁面與其它頁面是否同源~

根據定義,可以知道 A 和 B 同源,而 A 和 C、D、E 不同源。A、B 頁面同源是因為其協議(都是 http)、域名(都是 xys.ttsy)和埠(都是 80)都相同;而 A 與 C、D、E 不同源,是因為 A 和 C 不同協議(http 和 https),A 和 D 不同域名(xys.ttsy 和 d.xys.ttsy),A 和 E 不同埠(80 和 8081) 。

在瀏覽器中,一個最核心也最基本的安全功能便是同源策略。

同源策略是指瀏覽器中一個源的腳本只能訪問同源的另一個腳本的策略。

也就是說,在瀏覽器中的腳本如果要訪問其它腳本的話,那麼兩個腳本必須是同源的,否則會受到瀏覽器同源策略的限制。如果兩個腳本非同源,會有三個行為受到限制

DOM 無法獲得;

Cookie、LocalStorage 和 IndexDB 無法共享;

Ajax 請求限制;

DOM 無法獲得

DOM 無法獲得的限制最常見的是在 iframe 窗口與父窗口之間,如果父窗口與其 iframe 窗口的腳本是不同源的,則它們互相無法獲取對方的 DOM 元素。

如下父窗口與 iframe 不同源,父窗口中無法獲取 iframe 窗口中腳本的 DOM 元素

上述代碼列印出來的效果如下所示

同理,在 iframe 窗口腳本中也無法獲取父窗口腳本的 DOM 元素

那麼,有沒有什麼方式能夠規避此類同源策略的限制呢?答案是有的,只是這其中也是有條件的。

當父窗口與 iframe 窗口一級域名相同而二級域名不同的時候(或者說有共同的一級域名更為準確一點),則可以通過設置 document.domain 屬性來規避此類同源策略的限制。

只要分別在兩個窗口中對應的腳本文件中設置如下代碼即可

Cookie、LocalStorage 和 IndexDB 無法共享

若兩個腳本不同源,則 Cookie、LocalStorage 和 IndexDB 的內容無法共享。

對於 Cookie 來說,有兩種方式可以規避此類同源策略的限制。

若是一級域名相同而二級域名不同的情況(或者說有共同的一級域名更為準確一點),則可以通過設置 document.domain 屬性來規避此類同源策略的限制。

只要兩個腳本設置相同的 document.domain 值,即可共享 Cookie 。

第二種方式則是伺服器端代碼在設置 Cookie 的時候,將 domian 屬性設置為一級域名,那麼該一級域名下的子域名同樣可以共享 Cookie 。

而 LocalStorage 和 IndexDB 則無法通過上述方法來規避同源策略。

而對於完全不同源的頁面來說,還可以通過 window.name、window.postMessage 等方式來實現通訊,本篇不繼續贅述,有興趣的童鞋可以查閱相關資料了解。

Ajax 請求限制

在一個腳本中,如果通過 Ajax 請求另一個非同源的腳本,則會報錯。報錯信息經常會類似下面醬紫

這即是我們經常提到的 Ajax 跨域問題,這是由於瀏覽器的同源策略引起的,Ajax 無法請求非同源的資源。

對於 Ajax 跨域解決方案,通常來說有如下三種:

JSONP

CORS

代理伺服器

下面就詳細描述上述三種 Ajax 跨域解決方案。

JSONP

JSONP 是解決跨域很常用的一種方法了,其原理是通過 標籤向伺服器端發起請求不受瀏覽器同源策略的限制。而伺服器端在接受到請求後,可以返回一個指定名字的函數,該函數的參數是需要返回的數據。

舉個例子吶~

上述代碼通過創建一個 script 標籤,將其 src 屬性設置為執行請求的 url 並將其插入到頁面中,向伺服器發起一個請求。上述代碼中請求的 url 為 http://ttsy.com/getName?callback=fn ,指定了回調函數名為 fn 。

而服務端在收到該請求後返回一個指定名字的函數,該函數的參數是需要返回的數據。服務端返回數據如下

由於通過 script 標籤請求到的數據會直接執行,所以上述服務端返回數據後會直接執行 fn 函數,所以在上述代碼中 fn 函數將會輸出 name:ttsy 。

基於 JSONP 的實現原理,其只能通過 get 請求來獲得數據,不能進行較為複雜的 post 請求,所以在更多的情況下,我們會採用下面的 CORS 來解決 Ajax 的跨域問題。

CORS

CORS(Cross-origin resource sharing),全稱是跨域資源共享。它允許 Web 應用伺服器進行跨域訪問控制,從而使跨域數據傳輸得以安全進行。是 Ajax 跨域問題的根本解決方案。

CORS 的實現需要瀏覽器與伺服器共同支持。

目前來說,基本所有的瀏覽器都支持 CORS 功能,當瀏覽器發現 Ajax 跨域請求時,會在 HTTP 請求頭添加一些附加的頭信息,有時會多出一次 HTTP 請求,這些都是由瀏覽器自動完成的。

而在伺服器中要實現了 CORS 功能,則需要設置 Access-Control-Allow-Origin 屬性。

代理伺服器

代理伺服器是指通過設置一個同源的代理伺服器,然後將我們的 Ajax 請求發送到我們的代理伺服器上,再通過代理伺服器去向實際的伺服器去請求數據,最後通過代理伺服器返回給瀏覽器。

通過設置代理伺服器來規避瀏覽器同源策略的限制,其原理是伺服器之間的資源請求並沒有同源策略的限制。但是由於操作起來並不方便,所以在實際開發中並不會經常用這種方法來解決問題。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 淘淘笙悅 的精彩文章:

Chrome 開發者工具代碼行斷點調試

TAG:淘淘笙悅 |