[Javascript] cross domain 呼叫 iframe 裡面的 function,且呼叫 parent 的 function

2021-06-15


今天要來筆記一下一個可能是月經題,我有一個  parent.html 裡面嵌入了一個  son.html 這兩個位處於不同的 domain ,以前的年代可以很簡單的在 parent.html 裡面呼叫 son.html 裡面寫的 javascript function ,但是現在總是會出現..

Uncaught DOMException: Blocked a frame with origin "https://domain.com" from accessing a cross-origin frame.




1. 先敘述一下,我是要用 parent.html 呼叫 son.html 分別為 FuncA , FuncB 的兩個不同的 function ,並且我是需要取得回應值的。

2. 整理一下觀念,基本上現在要寫這樣的行為 其實是透過  postMessage 來做到 ,但是這觀念跟以前有點不一樣,傳統你會想成 , parent.html 呼叫 son.html  的 FuncA ,之後得到答案,但是現在思考的點應該是 parent.html 透過 postMessage 呼叫 son.html 的 FuncA ,之後 son.html 執行之後要透過 postMessage 去呼叫 parent.html 並且告訴他結果.

3. 還有一點該注意的,我這案例其中我規劃透過 postMessage 傳遞的時候我制定一個物件,其中包含 SourceType , Content , Func  。 SourceType 這邊主要判斷是不是自己寫的 程式來呼叫,因為我 Chrome 有裝一些數字錢包的外掛,它們也都是透過 postMessage 來 呼叫 function ,這就導致一堆呼叫進來的東西。Content 就是我要傳遞的資料,Func 就是判斷 呼叫哪一個 function


Source Code parent.htm:

<script src='https://code.jquery.com/jquery-3.6.0.min.js'></script> <iframe src="https://localhost:44344/son.html" frameBorder="0" style="width:100%;height:100px" id="codeMain"></iframe> <button type="button" id="btnA"> test1 </button> <button type="button" id="btnB"> test2 </button> <script> var iframeObj=document.getElementById("codeMain").contentWindow; $('#btnA').click(function () { var data = {}; //SourceType 帶入 DMIXEDITOR 代表是我們自己傳遞的 data.SourceType = 'DMIXEDITOR'; //主要傳遞的資料 data.Content = 'HELLO'; //給son做判別·要呼叫的是 FuncA data.Func = 'FUNCA'; //關鍵是後面的要帶入'*' iframeObj.postMessage(data, '*'); }); $('#btnB').click(function () { var data = {}; data.SourceType = 'DMIXEDITOR'; data.Content =2; data.Func = 'FUNCB'; document.getElementById("codeMain").contentWindow.postMessage(data, '*'); }); function receiveMessage(e) { //判斷從 son 回 call 回來的地方 if (!e.data.hasOwnProperty('SourceType')) { } else { //是我族類我才執行呼叫 if (e.data.SourceType == 'DMIXEDITOR') { alert(JSON.stringify(e.data)); } } } // 監聽 message 事件 window.addEventListener('message', receiveMessage, false); </script>


Source Code son.html:

<script> function receiveMessage(e) { if (!e.data.hasOwnProperty('SourceType')) { } else { //是我族類我才呼叫 if (e.data.SourceType === 'DMIXEDITOR') { //判斷 是 FUNCA 就 執行 FuncA 要做的 if (e.data.Func === 'FUNCA') { var data = {}; data.SourceType = 'DMIXEDITOR'; //加一點料證明 son 被呼叫過 data.Content = e.data.Content + " -CALLED_IFRAME_FUNCA"; //回傳給 parent.html parent.postMessage(data, '*'); } if (e.data.Func === 'FUNCB') { var data = {}; data.SourceType = 'DMIXEDITOR'; data.Content = (e.data.Content += 99); parent.postMessage(data, '*'); } } } } // 監聽 message 事件 window.addEventListener('message', receiveMessage, false); </script>


大概就是這樣,紀錄一下,這裡面比較 tricky 的就是 domain 的部分要帶入 '*' 之前我乖乖地填寫 domain 結果我在 jsfiddle 上面測試都沒有過..

紀錄一下給需要的人..


jsfiddle 屍體 : https://jsfiddle.net/no2don/pfdtz7yk/31/

reference :

https://rockjins.js.org/2017/05/05/2017-05-05-iframe-cross-domain-Communication/

https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage


當麻許的碎念筆記 2014 | Donma Hsu Design.