超詳細而且帶 Demo 的 JavaScript 跨域指南來了!javascript
本文基於你瞭解 JavaScript 的同源策略,而且瞭解使用跨域跨域的理由。html
首先要介紹的跨域方法必然是 JSONP。java
如今你想要獲取其餘網站上的 JavaScript 腳本,你很是高興的使用 XMLHttpRequest 對象來獲取。可是瀏覽器一點兒也不配合你,無情的彈出了下面的錯誤信息:git
XMLHttpRequest cannot load http://x.com/main.dat. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://y.com' is therefore not allowed access.
你內心確定會想,我難道要用後臺作個爬蟲來獲取這個數據嗎?!(;°○° )
爲了不這種蛋疼的事情發生,JSONP 就派上用場了。github
<script>
標籤是不受同源策略的限制的,它能夠載入任意地方的 JavaScript 文件,而並不要求同源。segmentfault
因此 JSONP 的理念就是,我和服務端約定好一個函數名,當我請求文件的時候,服務端返回一段 JavaScript。這段 JavaScript 調用了咱們約定好的函數,而且將數據當作參數傳入。
很是巧合的一點(其實並非),JSON 的數據格式和 JavaScript 語言裏對象的格式正好相同。因此在咱們約定的函數裏面能夠直接使用這個對象。跨域
光說不練假把式,讓咱們來看一個例子:瀏覽器
你須要獲取數據的頁面 index.html:安全
<script> function getWeather(data) { console.log(data); } </script> <script src="http://x.y.com/xx.js">
http://x.y.com/xx.js 文件內容:框架
getWeather({ "城市": "北京", "天氣": "大霧" });
咱們能夠看到,在咱們定義了 getWeather(data)
這個函數後,直接載入了 xx.js。
在這個腳本中,執行了 getWeather
函數,並傳入了一個對象。而後咱們在這個函數中將這個對象輸出到 console 中。
這就是整個 JSONP 的流程。
使用條件:
window
對象的引用。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 中輸入代碼:
document.domain = 'baidu.com'; var otherWindow = window.open('http://zhidao.baidu.com/');
咱們如今已經發現百度知道的網頁已經打開了,在百度知道網頁的 console 中輸入如下代碼:
document.domain = 'baidu.com';
如今回到百度文庫的網頁,咱們就可使用百度知道網頁的 window
對象來操做百度知道的網頁了。例如:
var divs = otherWindow.document.getElementsByTagName('div');
上面這個例子的使用方法並不常見,可是很是詳細的說明了這種方法的原理。
這種方法主要用在控制 <iframe>
的狀況中。
好比個人頁面(http://one.example.com/index.... <iframe>
:
<iframe id="iframe" src="http://two.example.com/iframe.html"></iframe>
咱們在 iframe.html 中使用 JavaScript 將 document.domain
設置好,也就是 example.com。
在 index.html 執行如下腳本:
var iframe = document.getElementById('iframe'); document.domain = 'example.com'; iframe.contentDocument; // 框架的 document 對象 iframe.contentWindow; // 框架的 window 對象
這樣,咱們就能夠得到對框架的徹底控制權了。
補充知識(絕對乾貨):
當兩個頁面不作任何處理,可是使用了框架或者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
只讀
咱們來看如下一個場景:
隨意打開一個頁面,輸入如下代碼:
window.name = "My window's name"; location.href = "http://www.qq.com/";
再檢測 window.name
:
window.name; // My window's name
能夠看到,若是在一個標籤裏面跳轉網頁的話,咱們的 window.name
是不會改變的。
基於這個思想,咱們能夠在某個頁面設置好 window.name
的值,而後跳轉到另一個頁面。在這個頁面中就能夠獲取到咱們剛剛設置的 window.name
了。
因爲安全緣由,瀏覽器始終會保持
window.name
是string
類型。
這個方法也能夠應用到與 <iframe>
的交互上來。
個人頁面(http://one.example.com/index.... <iframe>
:
<iframe id="iframe" src="http://omg.com/iframe.html"></iframe>
在 iframe.html 中設置好了 window.name
爲咱們要傳遞的字符串。
咱們在 index.html 中寫了下面的代碼:
var iframe = document.getElementById('iframe'); var data = ''; iframe.onload = function() { data = iframe.contentWindow.name; };
定睛一看,爲毛線報錯?
細心的讀者們確定已經發現了,兩個頁面徹底不一樣源啊!
因爲 window.name 不隨着 URL 的跳轉而改變,因此咱們使用一個暗黑技術來解決這個問題:
var iframe = document.getElementById('iframe'); var data = ''; iframe.onload = function() { iframe.onload = function(){ data = iframe.contentWindow.name; } iframe.src = 'about:blank'; };
或者將裏面的 about:blank 替換成某個同源頁面(最好是空頁面,減小加載時間)。
補充知識:
about:blank
,javascript:
和data:
中的內容,繼承了載入他們的頁面的源。
這種方法與 document.domain
方法相比,放寬了域名後綴要相同的限制,能夠從任意頁面獲取 string
類型的數據。
在 HTML5 中, window
對象增長了一個很是有用的方法:
windowObj.postMessage(message, targetOrigin);
windowObj
: 接受消息的 Window 對象。message
: 在最新的瀏覽器中能夠是對象。targetOrigin
: 目標的源,*
表示任意。這個方法很是強大,無視協議,端口,域名的不一樣。下面是烤熟的栗子:
var windowObj = window; // 能夠是其餘的 Window 對象的引用 var data = null; addEventListener('message', function(e){ if(e.origin == 'http://jasonkid.github.io/fezone') { data = e.data; e.source.postMessage('Got it!', '*'); } });
message
事件就是用來接收 postMessage
發送過來的請求的。函數參數的屬性有如下幾個:
origin
: 發送消息的 window
的源。data
: 數據。source
: 發送消息的 Window
對象。https://github.com/JasonKid/f...
「JavaScript」兩種服務端相關跨域方法詳解 ← 反向代理、CORS方法請點這裏
以爲不錯的話按頂部的推薦,讓更多人看到吧~ㄟ(▔▽▔ㄟ)