1. ホーム
  2. Web制作
  3. html5

postMessageを用いたiframeのクロスドメイン通信問題の詳細な解決法

2022-01-14 15:06:03

今週は頭の痛いことに遭遇しました。別のサードパーティのウェブプロジェクトを私のウェブプロジェクトに組み込みたかったのです。最初に思いついたのはiframeを使うことでしたが、問題はサードパーティのウェブプロジェクトとやりとりすることで、同一生成元ポリシーに違反すること、そしてクロスドメインの問題に対処することが最大の頭痛の種でした。

要件は、私のページでいくつかのボタンをクリックし、リアルタイムでiframeのサブページにフィードバックし、サブページが応答することです。

最初に思い浮かんだ解決策は、NGINXを使用して、同じドメイン下にある2つのプロジェクトをプロキシすることでした。しかし、それは少し些細なことのように思えます。

windowオブジェクトの下に、クロスドメイン通信の問題を解決するために特別に設計されたpostMessageメソッドがあります。

について ポストメッセージ 以下、postMessageを使ってiframeのクロスドメイン通信を実現する方法を見ていきますが、実際に使ってみてからドキュメントに戻ると、感覚が全く違いますね。

まず、2つの異なるソースからの2つのページがあり、iframePage.html が index.html のサブページであると仮定して、シナリオをシミュレートしてみましょう。

<! -- index.html -->

<body style="border:5px solid #333;">

  <h1>this is index</h1>

  <iframe src=". /iframePage.html" id='myframe'></iframe>

</body>


<! -- iframePage -->

<body style="border:5px solid #333;">

  <h1>this is iframePage</h1>

</body>


さて、2つのiframeはソースが異なるため通信できず(クロスドメインの問題があるとして)、そこでpostMessageの出番となるわけです。

親ページから子ページへメッセージを送ってみましょう。

// idnex.html

// Get the iframe element
iFrame = document.getElementById('myframe')

// Send the message after the iframe is loaded, otherwise the subpage will not receive the message
iFrame.onload = function(){

  //Send a message immediately after the iframe is loaded
  iFrame.contentWindow.postMessage('MessageFromIndex1','*');

}

postMessageはwindowオブジェクトに搭載されていることが分かっているので、iframeが読み込まれたらiFrame.contentWindowを使ってiframeのwindowオブジェクトを取得し、postMessageメソッドを呼び出せば、サブページにメッセージを送ったのと同じ意味になります。

postMessageメソッドの第一引数は、送信するデータで、任意の生の型が使用可能です。

Gecko 6.0 (Firefox 6.0 / Thunderbird 6.0 / SeaMonkey 2.3) より前のバージョンでは、最初のパラメータは文字列でなければなりません。

postMessageメソッドの第2パラメータは、送信先のURLを設定します。現在のサブページのurlが設定されたものと一致しない場合、送信に失敗するので、これを*に設定し、すべてのurlの送信を許可するようにします。

postMessageメソッドには第3パラメータがありますが、これは高度な使い方で、ここでは説明しませんので、後でMDNで勉強してください。

iframePage.htmlにメッセージが送信され、メッセージを受信することができます。

// iframePage.html

// callback function
function receiveMessageFromIndex ( event ) {
  console.log( 'receiveMessageFromIndex', event )
}

//Listen to the message event
window.addEventListener("message", receiveMessageFromIndex, false);



あとは、サブページのメッセージイベントをリスニングして、イベントがプリントアウトされるのを見るためにコールバック関数をセットアップするだけです。

イベントオブジェクトのdataプロパティには、親ページから渡されたデータが格納されています。

もう一度、子ページから親ページへのデータ送信を試してみましょう。

// iframePage.html

// send a message to the parent page, with data as the object
parent.postMessage( {msg: 'MessageFromIframePage'}, '*');



親ページがデータを受信します。

//index.html

// callback function
function receiveMessageFromIframePage (event) {
    console.log('receiveMessageFromIframePage', event)
}

//Listen to the message event
window.addEventListener("message", receiveMessageFromIframePage, false);



なるほど、確かに異なるデータを送信することは可能ですね、この時点でデータはのオブジェクトです。

人々は、以下の場所に行くことができます。 ポストメッセージデモ をクリックすると、コードをクローンして試せます。

以上、本記事が皆様の学習のお役に立てれば幸いです。また、スクリプトハウスを応援していただければ幸いです。