JavaScript實作跨域的方法:1、利用jsonp跨域;2、利用修改「document.domain」來跨域;3、利用「window.name」來跨域;4、利用「window .postMessage」方法來跨領域。
本教學操作環境:windows10系統、javascript1.8.5版、Dell G3電腦。
這裡說的js跨域是指透過js在不同的域之間進行資料傳輸或通信,例如用ajax向一個不同的域請求數據,或透過js取得頁面中不同域的框架中(iframe)的資料。只要協定、網域、連接埠有任何一個不同,都被當作是不同的網域。
下表給出了相對http://store.company.com/dir/page.html同源偵測的結果:
一、透過jsonp跨域
在js中,我們直接用XMLHttpRequest請求不同域上的數據時,是不可以的。但是,在頁面上引入不同網域上的js腳本檔案卻是可以的,jsonp正是利用這個特性來實現的。 例如,有個a.html頁面,它裡面的程式碼需要利用ajax取得一個不同網域上的json數據,假設這個json資料位址是http://example.com/data.php,那麼a.html中的程式碼就可以這樣:2、透過修改document.domain來跨子域
#瀏覽器都有一個同源策略,其限制之一就是第一種方法中我們說的不能透過ajax的方法去請求不同來源中的文件。它的第二個限制是瀏覽器中不同域的框架之間是不能進行js的交互操作的。有一點需要說明,不同的框架之間(父子或同輩),是能夠獲取到彼此的window對象的,但蛋疼的是你卻不能使用獲取到的window對象的屬性和方法(html5中的postMessage方法是一個例外,還有些瀏覽器例如ie6也可以使用top、parent等少數幾個屬性),總之,你可以當做是只能獲取到一個幾乎無用的window對象。例如,有一個頁面,它的地址是http://www.example.com/a.html , 在這個頁面裡面有一個iframe,它的src是http://example.com/b.html, 很顯然,這個頁面與它裡面的iframe框架是不同域的,所以我們是無法透過在頁面中書寫js程式碼來取得iframe中的東西的:這時候,document.domain就可以派上用場了,我們只要把http://www.example.com/a.html 和http://example.com/b.html這兩個頁面的document .domain都設成相同的網域就可以了。但要注意的是,document.domain的設定是有限制的,我們只能把document.domain設定成自身或更高一級的父域,而主域必須相同。例如:a.b.example.com 中某文檔的document.domain 可以設成a.b.example.com、b.example.com 、example.com中的任一個,但是不可以設成c.a.b.example.com,因為這是當前域的子域,也不可以設成baidu.com,因為主域已經不相同了。
在頁面http://www.example.com/a.html 中設定document.domain:
在頁面http://example. com/b.html 中也設定document.domain,而且這也是必須的,雖然這個文件的domain就是example.com,但是還是必須顯示的設定document.domain的值:
#這樣我們就可以透過js存取到iframe中的各種屬性和物件了。
不過如果你想在http://www.example.com/a.html 頁面中透過ajax直接要求http://example.com/b.html 頁面,即使你設定了相同的document .domain也還是不行的,所以修改document.domain的方法只適用於不同子域的框架間的交互作用。如果你想透過ajax的方法去與不同子網域的頁面交互,除了使用jsonp的方法外,還可以用一個隱藏的iframe來做一個代理。原理就是讓這個iframe載入一個與你想要透過ajax取得資料的目標頁面處在相同的網域的頁面,所以這個iframe中的頁面是可以正常使用ajax去取得你要的資料的,然後就是透過我們剛剛講得修改document.domain的方法,讓我們能透過js完全控制這個iframe,這樣我們就可以讓iframe去發送ajax請求,然後收到的資料我們也可以獲得了。
3、使用window.name來進行跨域
window物件有name屬性,該屬性有個特徵:即在一個視窗(window)的生命週期內,視窗載入的所有的頁面都是共用一個window.name的,每個頁面對window.name都有讀寫的權限,window.name是持久存在一個視窗載入過的所有頁面中的,並不會因新頁面的載入而重置。
例如:有一個頁面a.html,它裡面有這樣的程式碼:
#再看看b.html頁面的程式碼:
a.html頁面載入後3秒,跳到了b.html頁面,結果是:
充當中間人的iframe想要取得到data.html的透過window.name設定的數據,只需要把這個iframe的src設為www.cnblogs.com/data.html就行了。然後a.html想要得到iframe所取得的數據,也就是想要得到iframe的window.name的值,還必須把這個iframe的src設為跟a.html頁面同一個域才行,不然根據前面講的同源策略,a.html是不能存取到iframe裡的window.name屬性的。這就是整個跨域過程。
看下a.html頁面的程式碼:
上面的程式碼只是最簡單的原理示範程式碼,你可以對使用js封裝上面的過程,例如動態的創建iframe,動態的註冊各種事件等等,當然為了安全,獲取完數據後,還可以銷毀作為代理的iframe。網路上也有很多類似的現成程式碼,有興趣的可以去找一下。
透過window.name來進行跨域,就是這樣子的。
4、使用HTML5中新引進的window.postMessage方法來跨域傳送資料
window.postMessage(message,targetOrigin) 方法是html5新引進的特性,可以使用它來向其它的window物件發送訊息,無論這個window物件是屬於同源或不同來源,目前IE8 、FireFox、Chrome、Opera等瀏覽器都已經支援window.postMessage方法。
呼叫postMessage方法的window物件是指要接收訊息的那一個window對象,該方法的第一個參數message為要傳送的訊息,類型只能為字串;第二個參數targetOrigin用來限定接收訊息的那個window物件所在的域,如果不想限定域,可以使用通配符* 。
需要接收訊息的window對象,可是透過監聽自身的message事件來取得傳過來的訊息,訊息內容儲存在該事件對象的data屬性中。
上面所說的向其他window物件發送訊息,其實就是指一個頁面有幾個框架的那種情況,因為每個框架都有一個window物件。在討論第二種方法的時候,我們說過,不同域的框架間是可以取得到對方的window物件的,而且也可以使用window.postMessage這個方法。下面看一個簡單的範例,有兩個頁面
#我們執行a頁面後得到的結果:
#我們看到b頁面成功的收到了訊息。
使用postMessage來跨域傳送資料還是比較直覺和方便的,但是缺點是IE6、IE7不支持,所以用不用還得根據實際需要來決定。
相關推薦:javascript學習教學
以上是JavaScript怎麼實作跨域的詳細內容。更多資訊請關注PHP中文網其他相關文章!