トップページ >  HTML5 >  クロスドキュメントメッセージング
初版2011/08/13: 最終更新日2011/08/13
クロスドキュメントメッセージング
目次
クロスドキュメントメッセージングとは
クロスドキュメントメッセージングとは

クロスドキュメントメッセージングは、異なるドメイン(及びオリジン)のフレーム間でメッセージ通信を行うメカニズムを提供します。

<iframe>要素などを使うと、一つのページの中に複数のページを内包することができます。
しかし、フレーム内のページは表示は出来るものの、親ページ(フレーム)からJavascriptなどで操作することはできません。
URLにパラメータをつけて、フレーム内のページを変更することは可能ですが、ページそのものが更新するために(時間、メモリ消費などの)コストがかかります。

Javascriptなどスクリプトからサイト(フレーム)間の操作を行うことをクロスサイトスクリプティングといいます。
このクロスサイトスクリプティング、セキュリティとプライバシー保護の観点から必要不可欠な制限です。
しかし、この制限により、異なるドメイン間での通信手段がなく、WEBアプリケーションの障害になる場合がありました。

また同じドメインでも、httpプロトコルとSSLプロトコルなど、プロトコルが変わっても操作及び通信できなくなります。
このような「スキーマ(httpなど):ドメイン名:ポート番号」の組み合わせを「オリジン(orgin)」といいます。
先のセキュリティとプライバシー保護の観点から制限は、異ドメイン間だけでなく、異オリジン間にも適用されます。
そのため、httpプロトコルとSSLプロトコルで通信ができません。

html5のクロスドキュメントメッセージング

html5では、クロスドキュメントメッセージング(Cross-document messaging)と呼ばれる仕様を導入することで、この問題の解決方法としています。
但し、異なるオリジン間のDOMを直接操作することはできません。
それそれのオリジンから、メッセージを送り、それを受信します。
オリジン間でメールのやりとりのようなことをすることで、異なるオリジン間をつなぎます。

各ブラウザの対応

クロスドキュメントメッセージングは、2011年8月現在以下のブラウザで対応しています。
FireFox 3.5~、Safari 4~、Opera 10.6~、Google Chrome 3~、IE 8~

クロスドキュメントメッセージングの使い方

次のサンプルスクリプトはクロスドキュメントメッセージングを使った例です。
※本来は異なるオリジン間で行いますが、本ページでは便宜上同一オリジン間にて通信を行います。

クロスドキュメントメッセージングは、ページ内にWindowProxyオブジェクトを用意します。
WindowProxyオブジェクトは、フレーム側のWindowsオブジェクトのことです。
内包するフレーム(<iframe>要素など)のcontentWindowプロパティで得ることができます。

フレーム(オリジン)間をつなぐのは「postMessage」メソッドです。
この「postMessage」メソッドで異なるオリジン間でデータのやりとりをします。

(WindowProxyオブジェクト).postMessage(メッセージ, 送信先オリジン)
フレーム(オリジン)間でデータのやりとりを行う唯一の方法です。
WindowProxyオブジェクトを用いてメッセージを送ります。
メッセージは、スカラー値のみです。
json形式で渡す場合、受け取り側で変換する必要があります。
第二引数には、送信先となるオリジンを指定します。
オリジンですので、「スキーマ(httpなど):ドメイン名:ポート番号」でOKです。
例)ページ「https://www.nail-kobe.com/html5/html5_2211.html」にメッセージを送る場合は、「https://www.nail-kobe.com」でOKです。
もし、WindowProxyオブジェクトのスキーマ、ホスト名、あるいは、ポートと異なる場合は、通信は成立しません。(イベントが伝達されない。)
これはパスワードなどを送る場合、途中で傍受するオリジンが存在すると悪用される可能性があります。
オリジンのチェックをすることで、不正な通信をブロックします。
第二引数まで必須です。

クロスドキュメントメッセージングのイベントは「onmessage」です。

(WindowProxyオブジェクト).onmessage:messageイベント
フレーム(オリジン)間でメッセージを受け取ったときに発生するイベントです。
第一引数にイベントオブジェクトが定義します。
クロスドキュメントメッセージングのイベントオブジェクトの特徴的なプロパティは以下の通りです。
data
postMessageメソッドで送られたメッセージです。
テキストとして受け取ります。
json形式の場合、eval関数などでの変換が必要です。
origin
postMessageメソッドの送信元のオリジンです。
不正実行を防ぐ場合に使います。
source
postMessageメソッドの送信元のWindowProxyオブジェクト(参照)です。
これを使うことで異なったオリジンのウィンドウ間で双方向の通信を確立することができます。

リスト1. クロスドキュメントメッセージングの例(親フレーム側=このページ)

<h5>送信内容</h5>
<form id="fm0201" onsubmit="return false;">
	<input id="inp0201" type="text" placeholder="メッセージ" />
	<button id="btn0201" onclick="go0201();">メッセージ送信</button>
</form>
<iframe id="frm0201" src="html5_2211.html" class="OurFrm" ></iframe>

<script type="text/javascript">
//messageイベントの定義
window.addEventListener( 'load', function(){
	//messageイベントのリスナをセット
	window.addEventListener( 'message', rcvMe, false);
}, false);

//受け取り側コールバック
function rcvMe(evt){
	/*
	子フレーム(ウインドウ)には送信できます。
	親フレーム(ウィンドウ)のは、IE、Safari、Chrome は問題ないのですが
	FireFox、Operaは、2011年8月現在 戻ってきません。(エラーにもなりません)
	*/

	var pnl = document.getElementById("resP");
	var org = 'http://www.nail-kobe.com';

	//受信オリジンのチェック
	if( evt.origin != org ){
		return;
	}

	//戻った結果を表示
	pnl.innerHTML = pnl.innerHTML + evt.data + "<br/>\n";

}

//送信ボタンのクリック
function go0201(){
	var msg = document.getElementById("inp0201");
	var frm = document.getElementById("frm0201");
	var org = 'http://www.nail-kobe.com';
	msg.value = ( msg.value === null ) ? "" : msg.value;
	msg.value = ( msg.value === false ) ? "" : msg.value;
	if( msg.value != "" ){
		frm.contentWindow.postMessage( msg.value, org );
	}
	else
	{
		alert('メッセージを入れてください。');
	}
}
</script>

リスト2. クロスドキュメントメッセージングの例(子フレーム側=html5_2211.html)

<dl id="rcvMsg"></dl>

<script type="text/javascript">
//messageイベントの定義
window.addEventListener( 'load', function(){
	//messageイベントのリスナをセット
	window.addEventListener( 'message', rcvMe, false);
}, false);

//受け取り側コールバック
function rcvMe(evt){
	var dl = document.getElementById("rcvMsg");
	var org = 'http://www.nail-kobe.com';

	//現在時刻
	var now = new Date();
	var nh = now.getHours();
	var nn = now.getMinutes();
	var ns = now.getSeconds();
	var tm = nh + ":" + nn + ":" + ns;

	//受信オリジンのチェック
	if( evt.origin != org ){
		return;
	}

	//受取時刻を返信
	var src = evt.source;
	var snd = tm + " 次を受け取りました。:" + evt.data;
	src.postMessage( snd, org );


	//受け取った内容の表示
	var msg = "\n";
	msg = msg + "<dt>オリジン</dt>\n";
	msg = msg + "<dd>" + evt.origin + "</dd>\n";
	msg = msg + "<dt>メッセージ</dt>\n";
	msg = msg + "<dd>" + evt.data + "</dd>\n";
	msg = msg + "<dt>受取時刻</dt>\n";
	msg = msg + "<dd>" + tm + "</dd>\n";
	dl.innerHTML = msg;
}
</script>

実装例

送信内容
送信履歴