🏊‍♂️

クロスドメインの中にiframeで埋め込んだ同一ドメインにpostMessage()する方法

2022/06/11に公開

かなりニッチな状況だが、こんなことがあった。

状況

ドメイン名が異なるサイトを<iframe />で埋め込み、そのサイトのさらに中に同一ドメインを<iframe />で埋め込んだ。親windowと孫windowが同一ドメインで、子ドメインだけ別ドメイン。

やりたいこと

親windowと孫windowとの間で双方向でやり取りがしたい!

通常であればpostMessage()を使う。

問題

だが、問題は子windowがクロスドメインだということ。
クロスドメインだとpostMessage()してもエラーになってしまう。

解決策

色々調べた結果解決策を見つけた!!  のでシェア。

孫windowから親windowへのpostMessage()

これはシンプル。
親windowはブラウザのトップに存在しているので指定し易い。

window.top.postMessage({hoge:'hoge'})

https://developer.mozilla.org/ja/docs/Web/API/Window/top

親windowから孫windowへのpostMessage()

こちらが厄介だった。
親windowから見て孫windowを取得するにはどうしても別ドメインである子windowを経由するしかないと思っていた。
子windowを介さず、親windowが孫windowを取得する方法。探したらあった。postMessage()を活用する。

https://developer.mozilla.org/ja/docs/Web/API/Window/postMessage

ドキュメントをよく読むと、「配信されるイベント」の項目に、配信されたメッセージを取得できると書いてある。
その中のsourceが

メッセージを送った window オブジェクトへの参照。

まさに求めていたもの。

これを用いるとサンプルコードはこうなる。

grandchild.js
window.top.postMessage({messageType:registGrandchildWindow})
parent.js
let grandchildWindow = {}
const onMessage = (event) => {
  if (event.origin === location.origin && event.data) {
    switch (event.data.messageType) {
      case 'registGrandchildWindow':
	grandchildWindow = event.source
        break
    }
  }
}
window.addEventListener('message', onMessage, false)

/* 中略  */

grandchildWindow.postMessage({hoge:hoge})

やっていることは以下の通り。

  1. 孫windowから親windowにpostMessage()
  2. 受け取ったmessageのsourceから孫windowを取得
  3. 孫window.postMessage()
if (event.origin === location.origin && event.data) {

ここは今回とは直接関係ないが不正なメッセージを除外するために入れている。

ドキュメントはよく読もう!

Discussion