您當(dāng)前位置:圖趣網(wǎng)(Tuquu) >> 網(wǎng)頁設(shè)計教程 >> 移動前端 >> 瀏覽設(shè)計教程

父子頁面之間跨域通信的方法

由于同源策略的限制,JavaScript跨域的問題,一直是一個比較棘手的問題,為了解決頁面之間的跨域通信,大家煞費苦心,研究了各種跨域方案。之前也有小網(wǎng)同學(xué)分享過一篇“跨域,不再糾結(jié)” 開始照著嘗試時還是有些不夠明白的地方,深入了解之后,這里給大家補充一點更具體的做法。

先來看看哪些情況下才存在跨域的問題:

 

編號 URL 說明 是否允許通信

1

http://www.a.com/a.js http://www.a.com/b.js

同一域名下

允許

2

http://www.a.com/lab/a.js http://www.a.com/script/b.js

同一域名下不同文件夾

允許

3

http://www.a.com:8000/a.js http://www.a.com/b.js

同一域名,不同端口

不允許

4

http://www.a.com/a.js https://www.a.com/b.js

同一域名,不同協(xié)議

不允許

5

http://www.a.com/a.js http://70.32.92.74/b.js

域名和域名對應(yīng)ip

不允許

6

http://www.a.com/a.js http://script.a.com/b.js

主域相同,子域不同

不允許

7

http://www.a.com/a.js http://a.com/b.js

同一域名,不同二級域名(同上)

不允許(cookie這種情況下也不允許訪問)

8

http://www.a.com/a.js http://www.b.com/b.js

不同域名

不允許

其中編號6、7兩種情況同屬于主域名相同的情況,可以設(shè)置domain來解決問題,今天就不討論這種情況了。 對于其他跨域通信的問題,我想又可以分成兩類,其一(第一種情況)是a.com下面的a.js試圖請求b.com下某個接口時產(chǎn)生的跨域問題。其二(第二種情況)是當(dāng)a.com與b.com下面的頁面成父子頁面關(guān)系時試圖互相通信時產(chǎn)生的跨域問題,典型的應(yīng)用場景如a.com/a.html使用iframe內(nèi)嵌了b.com/b.html,大家都知道a.html內(nèi)的js腳本試圖訪問b.html時是會被拒絕的,反之亦然。 第一種情況,目前主流的方案是JSONP,高版本瀏覽器支持html5的話,還可以使用XHR2支持跨域通信的新特性。 第二種情況,目前主要是通過代理頁面或者使用postMessageAPI來做,這也是今天要討論的話題。 第二種情況,有這樣一些類似的案例:a.com/a.html使用iframe內(nèi)嵌了b.com/b.html,現(xiàn)在希望iframe的高度能自動適應(yīng)b.html的高度,使iframe不要出現(xiàn)滾動條。我們都知道跨域了,a.html是沒辦法直接讀取到b.html的高度的,b.html也沒辦法把自己的高度告訴a.html。 直接說可以用代理頁面的方法搞定這個問題吧,但是怎么代理法,先來看下面這張圖:

1 圖1

b.html與a.html是不能直接通信的。我們可以在b.html下面再iframe內(nèi)嵌一個proxy.html頁面,因為這個頁面是放在a.com下面的,與a.html同域,所以它其實是可以和a.html直接通信的,假如a.html里面有定義一個方法_callback,在proxy.html可以直接top._callback()調(diào)用它。但是b.html本身和proxy.html也是不能直接通信的,所謂代理頁面的橋梁作用怎么實現(xiàn)呢? b.html內(nèi)嵌proxy.html是通過一段類似下面這樣的代碼: <iframe id=”proxy” src=”a.com/proxy.html” name=”proxy” frameborder=”0″ width=”0″ height=”0″></iframe> 這個iframe的src屬性b.html是有權(quán)限控制的。如果它把src設(shè)置成a.com/proxy.html?args=XXX,也就是給url加一個查詢字符串,proxy.html內(nèi)的js是可以讀取到的。對的,這個url的查詢字符串就是b.html和proxy.html之間通信的橋梁,美中不足的是每次通信都要重寫一次url造成一次網(wǎng)絡(luò)請求,這有時會對服務(wù)器及頁面的運行效率產(chǎn)生很大的影響。同時由于參數(shù)是通過url來傳遞的,會有長度和數(shù)據(jù)類型的限制,搜集的資料顯示:

  • IE瀏覽器對URL的長度現(xiàn)限制為2048字節(jié)。
  • 360極速瀏覽器對URL的長度限制為2118字節(jié)。
  • Firefox(Browser)對URL的長度限制為65536字節(jié)。
  • Safari(Browser)對URL的長度限制為80000字節(jié)。
  • Opera(Browser)對URL的長度限制為190000字節(jié)。
  • Google(chrome)對URL的長度限制為8182字節(jié)。

上面的方法,通過迂回戰(zhàn)術(shù)實現(xiàn)了b.html跟a.html通信,但是倒過來,a.html怎么跟b.html通信呢?嵌入在b.html里面的proxy.html可以用top快速的聯(lián)系上a.html,但是要想讓a.html找到proxy.html就不容易了,夾在中間的 b.html生生把它們分開了,a.html沒法讓b.html去找到proxy.html然后返回給它。只能采用更迂回的戰(zhàn)術(shù)了。 順著前面b.html到a.html的通信過程,逆向的想一下,雖然a.html沒有辦法主動找到proxy.html,但是proxy.html可以反過來告訴a.html它在哪里: 在proxy.html加這么一段腳本:

1 var topWin = top;
2 function getMessage(data) {
3     alert("messageFormTopWin:" + data);
4 }
5 function sendMessage(data) {
6     topWin.proxyWin = window;
7     topWin.getMessage(data);
8 }

在a.html加這么一段腳本:

01 var proxyWin = null;
02 function getMessage(data) {
03     alert("messageFormProxyWin:"+data);
04     sendMessage("top has receive data:"+data);
05 }
06  
07 function sendMessage(data) {
08     if (null != proxyWin) {
09         proxyWin.getMessage(data);
10     }
11 }

也就是必須由proxy.html先主動發(fā)送一個消息給a.html,a.html得到proxy.html頁面window的引用,就可以反過來向它發(fā)送請求了。 現(xiàn)在a.html可以把消息發(fā)給proxy.html了,但是proxy.html怎么把消息轉(zhuǎn)送到b.html?似乎這才是難點,因為它們之間才真正有著“跨域”這一道鴻溝。 這回我們不再用前面那個iframe內(nèi)嵌代理頁面的方法再在proxy.html內(nèi)嵌一個b.com下面的代理頁面了,這樣實在會給人感覺嵌的太深了,四層。但是為了跨越這道鴻溝,b.com下面也加一個代理頁面是免不的。不過現(xiàn)在我們要利用一下window.name。window.name有一個特性,就是頁面在同一個瀏覽器窗口(標(biāo)簽頁)中跳轉(zhuǎn)時,它一直存在而且值不會改變。比如我們在a.html中設(shè)置了window.name=”a”,然后location.href=”http://b.com/b.html”跳轉(zhuǎn)后,b.html可以讀取window.name的值為”a”;而且window.name的值長度一般可以到達2M,ie和firefox甚至可以達到32M,這樣的存儲容量,足夠利用起來做跨域的數(shù)據(jù)傳遞了。好吧,我們現(xiàn)在要做的就是當(dāng)proxy.html拿到a.html發(fā)送過來的數(shù)據(jù)后把這個數(shù)據(jù)寫入window.name中,然后跳轉(zhuǎn)到b.com下面的代理頁面,我們這里假設(shè)是bproxy.html。bproxy.html讀取到window.name值后,通知給它父頁面b.html就簡單了。我們再來看這個過程可以用圖大概示意一下:

2 圖2

圖例中綠色的雙向箭頭表示可以通信,橙色的雙向箭頭表示不能直接通信。 最后我們簡單看一下雙向通信的實測效果:

3 圖3

b.html每次加載的時候都先給a.html發(fā)一個”連接請求”,讓a.html可以找到proxy.html。所以頁面第一次加載的時候會產(chǎn)生三個請求:

4 圖4

每次b.html向a.html發(fā)送消息的時候會產(chǎn)生一個請求:

5 圖5

每次a.html向b.html發(fā)送消息的時候會產(chǎn)生兩個請求,其中一個是a.com/proxy.html向b.com/bproxy.html跳轉(zhuǎn)產(chǎn)生的,另一個是b.html重新向a.html發(fā)起“連接請求”時產(chǎn)生的:

6

[教程作者:admin]
免責(zé)聲明:本站文章系圖趣網(wǎng)整理發(fā)布,如需轉(zhuǎn)載,請注明出處,素材資料僅供個人學(xué)習(xí)與參考,請勿用于商業(yè)用途!
本文地址:http://m.likemindfilms.com/tutorial/wd1633.html
網(wǎng)站性能優(yōu)化之CSS無圖片技術(shù)
5項移動支付絕不能忽略的細(xì)節(jié)
圖趣網(wǎng)微信
建議反饋
×