「JavaScript」四種跨域方式詳解

發表於2015-09-02

超詳細並且帶 Demo 的 JavaScript 跨域指南來了!

本文基於你瞭解 JavaScript 的同源策略,並且瞭解使用跨域跨域的理由。

1. JSONP

首先要介紹的跨域方法必然是 JSONP。

現在你想要獲取其他網站上的 JavaScript 指令碼,你非常高興的使用 XMLHttpRequest 物件來獲取。但是瀏覽器一點兒也不配合你,無情的彈出了下面的錯誤資訊:

你心裡肯定會想,我難道要用後臺做個爬蟲來獲取這個資料嗎?!(;°○° )
為了避免這種蛋疼的事情發生,JSONP 就派上用場了。

<script>  標籤是不受同源策略的限制的,它可以載入任意地方的 JavaScript 檔案,而並不要求同源。

所以 JSONP 的理念就是,我和服務端約定好一個函式名,當我請求檔案的時候,服務端返回一段 JavaScript。這段 JavaScript 呼叫了我們約定好的函式,並且將資料當做引數傳入。
非常巧合的一點(其實並不是),JSON 的資料格式和 JavaScript 語言裡物件的格式正好相同。所以在我們約定的函式裡面可以直接使用這個物件。

光說不練假把式,讓我們來看一個例子:

你需要獲取資料的頁面 index.html:

http://x.y.com/xx.js 檔案內容:

我們可以看到,在我們定義了 getWeather(data)  這個函式後,直接載入了 xx.js。
在這個指令碼中,執行了  getWeather  函式,並傳入了一個物件。然後我們在這個函式中將這個物件輸出到 console 中。

這就是整個 JSONP 的流程。

2. document.domain

使用條件:

  1. 有其他頁面 window 物件的引用。
  2. 二級域名相同。
  3. 協議相同。
  4. 埠相同。

document.domain  預設的值是整個域名,所以即使兩個域名的二級域名一樣,那麼他們的 document.domain 也不一樣。

使用方法就是將符合上述條件頁面的 document.domain 設定為同樣的二級域名。這樣我們就可以使用其他頁面的 window 物件引用做我們想做的任何事情了。(╯▔▽▔)╯

補充知識:

  • x.one.example.com 和 y.one.example.com 可以將 document.domain 設定為 one.example.com,也可以設定為 example.com。
  • document.domain  只能設定為當前域名的一個字尾,並且包括二級域名或以上(.edu.cn 這種整個算頂級域名)。

我們直接操刀演示,用兩個網站 http://wenku.baidu.com/http://zhidao.baidu.com/
這兩個網站都是 http 協議,埠都是 80, 且二級域名都是 baidu.com。

開啟 http://wenku.baidu.com/,在 console 中輸入程式碼:

我們現在已經發現百度知道的網頁已經開啟了,在百度知道網頁的 console 中輸入以下程式碼:

現在回到百度文庫的網頁,我們就可以使用百度知道網頁的 window 物件來操作百度知道的網頁了。例如:

上面這個例子的使用方法並不常見,但是非常詳細的說明了這種方法的原理。
這種方法主要用在控制  <iframe>  的情況中。

比如我的頁面(http://one.example.com/index.html)中內嵌了一個 <iframe> :

我們在 iframe.html 中使用 JavaScript 將  document.domain  設定好,也就是 example.com。

在 index.html 執行以下指令碼:

這樣,我們就可以獲得對框架的完全控制權了。

補充知識(絕對乾貨):
當兩個頁面不做任何處理,但是使用了框架或者 window.open() 得到了某個頁面的 window 物件的引用,我們可以直接訪問的屬性有哪些?

方法
window.blur
window.close
window.focus
window.postMessage
window.location.replace
屬性 許可權
window.closed 只讀
window.frames 只讀
window.length 只讀
window.location.href 只寫
window.opener 只讀
window.parent 只讀
window.self 只讀
window.top 只讀
window.window 只讀

3. window.name

我們來看以下一個場景:

隨意開啟一個頁面,輸入以下程式碼:

再檢測  window.name  :

可以看到,如果在一個標籤裡面跳轉網頁的話,我們的 window.name 是不會改變的。
基於這個思想,我們可以在某個頁面設定好 window.name  的值,然後跳轉到另外一個頁面。在這個頁面中就可以獲取到我們剛剛設定的 了。

由於安全原因,瀏覽器始終會保持 window.namestring 型別。

這個方法也可以應用到與 <iframe> 的互動上來。

我的頁面(http://one.example.com/index.html)中內嵌了一個  <iframe>  :

在 iframe.html 中設定好了  window.name  為我們要傳遞的字串。
我們在 index.html 中寫了下面的程式碼:

定睛一看,為毛線報錯?
細心的讀者們肯定已經發現了,兩個頁面完全不同源啊!
由於 window.name 不隨著 URL 的跳轉而改變,所以我們使用一個暗黑技術來解決這個問題:

或者將裡面的 about:blank 替換成某個同源頁面(最好是空頁面,減少載入時間)。

補充知識:
about:blank , javascript: 和 data: 中的內容,繼承了載入他們的頁面的源。

這種方法與 document.domain 方法相比,放寬了域名字尾要相同的限制,可以從任意頁面獲取 string 型別的資料。

4. [HTML5] postMessage

在 HTML5 中, window 物件增加了一個非常有用的方法:

  • windowObj : 接受訊息的 Window 物件。
  • message : 在最新的瀏覽器中可以是物件。
  • targetOrigin : 目標的源,* 表示任意。

這個方法非常強大,無視協議,埠,域名的不同。下面是烤熟的栗子:

message 事件就是用來接收 postMessage 傳送過來的請求的。函式引數的屬性有以下幾個:

  • origin : 傳送訊息的 window 的源。
  • data : 資料。
  • source : 傳送訊息的 Window 物件。

Demo

https://github.com/JasonKid/fezone/tree/master/JavaScript/%E5%87%A0%E7%A7%8D%E8%B7%A8%E5%9F%9F%E6%96%B9%E6%A1%88%E8%AF%A6%E8%A7%A3

兩種服務端相關跨域方法

「JavaScript」兩種服務端相關跨域方法詳解

相關文章