js中各種跨域問題實戰小結(二)


這里接上篇:js中各種跨域問題實戰小結(一)

后面繼續學習的過程中,對上面第一篇有稍作休整。下面繼續第二部分:

 

-->5.利用iframe和location.hash

-->6.window.name跨域實現

 

 

利用iframe和location.hash實現跨域

想必有很多人像我之前一樣,或許只知道上面文中所說的那幾種方法。所以,我剛了解到可以用iframe和location.hash來實現跨域的時候,我會想,為什么他們可以實現。iframe是什么,有什么特性,location.hash是什么又有什么特性。

 

准備:

>>1.MDN上說的<iframe>:HTML 的<iframe>(HTML inline框架元素)是一個嵌套的瀏覽上下文,他可以有效地嵌入另一個HTML頁面到當前頁面。在HTML 4.01中,一個文件可能包含一個頭和一個身體或頭部和一個框架集,而不是一個身體和一個框架集。然而,一個< iframe >可以被應用在正常的文件體。每個瀏覽上下文有它自己的會話歷史和活動文檔。瀏覽上下文包含嵌入的內容叫做父瀏覽上下文。頂級的瀏覽上下文沒有父是典型的瀏覽器窗口

了解到了<iframe>,我覺得另外兩個相似的標簽<frame>和<frameset>可以一起拿過來看下啦,這有篇文章放在一起總結了下:Frameset,Frame和Iframe

 

>>2.window.location:打開chrome的console,一起來試一下,很快就懂啦。我們從最基本的開始:

2.1 可以跳轉到另一個頁面:打開百度搜索的主頁,然后在console中輸入下面代碼:

window.location = "http://www.cnblogs.com/skylar/";

看,是不是跳轉到我的博客主頁啦。

2.2 強制從服務器重新加載頁面:既然來到了我的博客主頁,就先別走,繼續輸入下面代碼:

window.location.reload(true);

可以看到頁面被重新加載了。

2.3 然后可以點擊進去比如js中各種跨域問題實戰小結(一)這篇文章,console輸入:

location.hash = '#comments';

看看頁面是不是跳到了最下面評論的位置。

其實還有兩個特性:比如說alert當前url屬性,通過修改window.location.search屬性向服務器發送一個字符串,這你可以移步這里自行腦補:MDN window.location 。

這里有用的是下面這個例子:location.hash理解demo

這里可以查看代碼:https://github.com/zhangmengxue,因為我們就是要利用location.hash的特性來加上iframe來實現跨域,看完了這個demo,我們就可以開始實現跨域了。(請用chrome打開,還有些需要總結的兼容性問題)

 

 

實現:

我為了模擬兩個不同的域,在SAE上面創建了兩個wordpress應用,如果你之前也不懂SAE是什么的話,這個小簡介:新浪SAE 會讓你大致了解到SAE是做什么的,如何開始使用它。我的兩個應用:

看到url了吧,是不同域喔,環境模擬好了,我可以開始嘗試跨域了。

在[http://1.daeskylar.sinaapp.com/]下有兩個文件 a.html和c.html;

在[http://1.skylarisdae.sinaapp.com/]下有文件 b.html

我想要在a.html中訪問我在b.html中模擬的數據Helloworld!

好呀,那現在點擊 有a.html和c.html的這個域 訪問我在這個域上的a.html文件,它應該會告訴你他是a.html頁面,然后他會訪問到了我放在b.html中的HelloWorld!

跨域這樣就實現了喔,那具體是怎樣實現的呢? 

 

原理:

a.html想和b.html通信(在a.html中動態創建一個b.html的iframe來發送請求);

但是由於“同源策略”的限制他們無法進行交流(b.html無法返回數據),於是就找個中間人:與a.html同域的c.html;

b.html將數據傳給c.html(b.html中創建c.html的iframe),由於c.html和a.html同源,於是可通過c.html將返回的數據傳回給a.html,從而達到跨域的效果。

三個頁面之間傳遞參數用的是location.hash,改變hash並不會導致頁面刷新(這點很重要)。

------------------------------------------------------------------------------------------------------------------------------------------------                                

a.html---①--->b.html----②--->c.html---③--->a.html——>a.html便獲得到了b.html中的數據

①通過iframe的location.hash傳參數給b.html  ;

②通過iframe的location.hash傳參數給c.html ;

 ③同域傳給a.html。

-------------------------------------------------------------------------------------------------------------------------------------------------

 

代碼:

a.html:

 1 <!doctype html>
 2 <html>
 3 <head>
 4 <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
 5 <title>localhost:a.html</title>
 6 
 7 <style type="text/css">
 8 
 9 </style>
10 </head>
11 
12 <body>
13 <script type="text/javascript">
14     alert('我是a頁面');
15 function sendRequest(){
16   //動態創建個iframe
17   var ifr = document.createElement('iframe');
18   ifr.style.display = 'none';
19   //跨域發送請求給b.html,參數是#sayHello
20   ifr.src = 'http://1.skylarisdae.sinaapp.com/b.html#sayHello';
21   document.body.appendChild(ifr);
22 }
23 function checkHash(){
24   var data = location.hash?location.hash.substring(1):'';
25   if(data){
26     //這里處理返回值
27     alert(data);
28     location.hash = '';
29   }
30 }
31 setInterval(checkHash,1000);
32 window.onload = sendRequest;
33 </script>
34 </body>
35 </html>
View Code

c.html:

 1 <!doctype html>
 2 <html>
 3 <head>
 4 <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
 5 <title>localhost:c.html</title>
 6 
 7 <style type="text/css">
 8 
 9 </style>
10 </head>
11 
12 <body>
13 <script type="text/javascript">
14 //因為c.html和a.html屬於同一個域,所以可以通過改變其location.hash的值,可以通過parent.parent獲取a.html的window對象
15 parent.parent.location.hash = self.location.hash.substring(1);
16 </script>
17 </body>
18 </html>
View Code

b.html:

 1 <!doctype html>
 2 <html>
 3 <head>
 4 <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
 5 <title>另某個域的:b.html</title>
 6 
 7 <style type="text/css">
 8 
 9 </style>
10 </head>
11 
12 <body>
13 <script type="text/javascript">
14 function checkHash(){
15     var data = '';
16     //模擬一個簡單的參數處理操作
17     switch(location.hash){
18         case '#sayHello':
19               data = 'HelloWorld';
20               break;
21         case '#sayHi':
22               data = 'HiWorld';
23               break;
24         default : break;
25     }
26     data && callBack('#'+data);
27 }
28 function callBack(hash){
29    var proxy = document.createElement('iframe');
30    proxy.style.display = 'none';
31    proxy.src = 'http://1.daeskylar.sinaapp.com/c.html'+hash;
32    document.body.appendChild(proxy);
33 }
34 window.onload = checkHash;
35 </script>
36 </body>
37 </html>
View Code

 

這里參考了:javascript跨域詳解

 

利用window.name實現跨域

 

實現:

我還是利用上面我在sae上面創建的應用:

在[http://1.daeskylar.sinaapp.com/]下有兩個文件 wantdata.html和proxy.html;

在[http://1.skylarisdae.sinaapp.com/]下有文件 data.html。

我想要在wantdata.html中訪問到我在data.html中存在window.name中的數據,是個字符串,就叫‘我拿到數據啦!’。

訪問這里:http://1.daeskylar.sinaapp.com/wantdata.html 應該可以看到alert出的數據喔。

 

原理:

MDN上的window.name是這樣說的:

窗口的名稱,主要用於設置超鏈接和表格對象。Windows不需要有名字

它也被用於提供跨域通信的一些框架(例如sessionvars和DojoDojoX。IOwindownameJSONP更安全的替代方案

 

window.name 的美妙之處在於:name 值在不同的頁面(甚至不同域名)加載后依舊存在,並且可以支持非常長的 name 值(2MB)。

這篇文章講解的非常詳細,很值得閱讀:使用window.name解決跨域問題

 

實現起來基本步驟如下: 

     1.創建一個iframe,把其src指向目標頁面(提供web service的頁面,該目標頁面會把數據附加到這個iframe的window.name上,大小一般為2M,IE和firefox下可以大至32M左右;數據格式可以自定義,如json字符串);

     2.監聽iframe的onload事件,在此事件中立即設置這個iframe的src指向本地域的某個頁面,由本地域的這個頁面讀取iframe的window.name。

     3.獲取數據以后銷毀這個iframe,釋放內存;這也保證了安全(不被其他域frame js訪問)。


總結起來即:iframe的src屬性由外域轉向本地域,跨域數據即由iframe的window.name從外域傳遞到本地域。這個就巧妙地繞過了瀏覽器的跨域訪問限制,但同時它又是安全操作。

 

代碼:

wantdata.html

 1 <!doctype html>
 2 <html>
 3 <head>
 4 <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
 5 <title>window.name跨域demo</title>
 6 
 7 <style type="text/css">
 8 
 9 </style>
10 </head>
11 
12 <body>
13 <script type="text/javascript">
14     var state = 0, 
15     iframe = document.createElement('iframe'),
16     loadfn = function() {
17         if (state === 1) {
18             var data = iframe.contentWindow.name;    // 讀取數據
19             alert(data);    //彈出'拿到數據啦!'
20             //下面立即銷毀iframe,釋放內存,也保證安全
21             iframe.contentWindow.document.write('');
22             iframe.contentWindow.close();
23             document.body.removeChild(iframe);
24         } else if (state === 0) {
25             state = 1;
26             iframe.contentWindow.location = "http://1.daeskylar.sinaapp.com/proxy.html";    // 設置的代理文件
27         }  
28     };
29     iframe.src = 'http://1.skylarisdae.sinaapp.com/data.html';
30     if (iframe.attachEvent) {
31         iframe.attachEvent('onload', loadfn);
32     } else {
33         iframe.onload  = loadfn;
34     }
35     document.body.appendChild(iframe);
36 </script>
37 </body>
38 </html>
View Code

data.html

 1 <!doctype html>
 2 <html>
 3 <head>
 4 <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
 5 <title>data頁</title>
 6 
 7 <style type="text/css">
 8 
 9 </style>
10 </head>
11 
12 <body>
13 <script type="text/javascript">
14     window.name = '拿到跨域的數據啦!';    // 這里是要傳輸的數據,大小一般為2M,IE和firefox下可以大至32M左右
15                                      // 數據格式可以自定義,如json、字符串
16 </script>
17 </body>
18 </html>
View Code

proxy.html

 1 <!doctype html>
 2 <html>
 3 <head>
 4 <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
 5 <title>window.name跨域demo</title>
 6 
 7 <style type="text/css">
 8 
 9 </style>
10 </head>
11 
12 <body>
13     <span>這里是代理空文件</span>
14 <script type="text/javascript">
15   
16 </script>
17 </body>
18 </html>
View Code

 

 這里參考了:window.name實現跨域數據傳輸    使用window.name解決跨域問題

 

 

從一大早寫到現在了,午覺也沒睡,寫不動了,后面再來個三吧,補上:

-->7.HTML5 postMessage實現跨域


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM