使用 postMessage 解決 iframe 跨域通信問題


使用 postMessage 解決 iframe 跨域通信問題
https://blog.csdn.net/erdfty/article/details/86518879

這周碰到一個讓人頭疼的需求:要在我的web項目中嵌入另一個第三方web項目。第一時間想到的就是用iframe了,但問題來了,我和第三方web項目是有交互的,這就違反同源策略了,處理跨域問題是最讓人頭疼的事之一。

需求是這樣的,在我的頁面點擊一些按鈕,要實時反饋到iframe子頁面,子頁面再進行響應。

當時腦子里第一時間想到的解決方案是:用NGINX把兩個項目代理到同一域名下。但這樣似乎有點小題大做了,有沒有更方便快捷的方法呢?

window對象下有個postMessage方法,是專門用來解決跨域通信問題的。

關於postMessage的詳細介紹請戳這里,不過MDN的文檔太詳細了,導致有些同學看完還是一臉懵逼,下面我們就來看看怎么用postMessage實現iframe跨域通信,當你會用了之后再回去看文檔,感覺是完全不同的。

首先我們模擬場景,假設有兩個不同源的頁面,iframePage.htmlindex.html的子頁面:


   
   
   
           
  1. <!-- index.html -->
  2. <body style="border:5px solid #333;">
  3. <h1>this is index </h1>
  4. <iframe src="./iframePage.html" id='myframe'> </iframe>
  5. </body>

   
   
   
           
  1. <!-- iframePage -->
  2. <body style="border:5px solid #333;">
  3. <h1>this is iframePage </h1>
  4. </body>

現在這兩個iframe是無法通信,因為它們是不同源的(假設存在跨域問題),這時候就要用到postMessage了。

我們先試着從父頁面向子頁面發送一條消息:


   
   
   
           
  1. // idnex.html
  2. //獲取iframe元素
  3. iFrame = document. getElementById( 'myframe')
  4. //iframe加載完畢后再發送消息,否則子頁面接收不到message
  5. iFrame. onload = function( ){
  6. //iframe加載完立即發送一條消息
  7. iFrame. contentWindow. postMessage( 'MessageFromIndex1', '*');
  8. }

我們知道postMessage是掛載在window對象上的,所以等iframe加載完畢后,用iFrame.contentWindow獲取到iframewindow對象,然后調用postMessage方法,相當於給子頁面發送了一條消息。

postMessage方法第一個參數是要發送的數據,可以是任何原始類型的數據。

Gecko 6.0 (Firefox 6.0 / Thunderbird 6.0 / SeaMonkey 2.3)之前,第一個參數必須是一個字符串。

postMessage方法第二個參數可以設置要發送到哪個url,如果當前子頁面的url和設置的不一致,則會發送失敗,我們設置為*,代表所有url都允許發送。

postMessage方法還有第三個參數,屬於高級用法,這里不做討論,可以稍后去MDN了解。

消息發送到iframePage.html,我們來接收message:


   
   
   
           
  1. // iframePage.html
  2. //回調函數
  3. function receiveMessageFromIndex ( event ) {
  4. console. log( 'receiveMessageFromIndex', event )
  5. }
  6. //監聽message事件
  7. window. addEventListener( "message", receiveMessageFromIndex, false);

我們只需要在子頁面監聽message事件,並且設置好回調函數即可,來看看打印出來的event

 

event對象中的data屬性存放着我們從父頁面傳過來的數據,就這么簡單!

讓我們再試試從子頁面發送數據給父頁面:


   
   
   
           
  1. // iframePage.html
  2. //給父頁面發送消息,data為對象
  3. parent. postMessage( { msg: 'MessageFromIframePage'}, '*');

父頁面接收數據:


   
   
   
           
  1. //index.html
  2. //回調函數
  3. function receiveMessageFromIframePage (event) {
  4. console. log( 'receiveMessageFromIframePage', event)
  5. }
  6. //監聽message事件
  7. window. addEventListener( "message", receiveMessageFromIframePage, false);

我看看到,的確可以傳輸不同的數據,此時data為一個對象:

 

大家自己把代碼clone下來運行試試看。

 


免責聲明!

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



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