JavaScript プログラミング講座

 

Web Messaging について

 


■ Web Messaging について

 
Web Messaging は、HTML5 世代の機能です。
 
http://www.w3.org/TR/webmessaging/ (Candidate Recommendation)
 
ブラウザから2つの Web ページを開き、相互にメッセージ通信を行う事ができます。
 
これはネットを経由する通信ではなく、クライアント内だけのやり取りです。
 
■生成元(オリジン)について
 
生成元(オリジン)とは、自身のリソースが格納されている場所です。
 
プロトコルドメインポート番号」の3つを合わせたものです。
 
 
■同一生成元ポリシー (Same-Origin Policy) について
 
クロスサイトスクリプトを行う事はできません。
 
例えば、「http://my.example.com」をブラウザで開くとします。
 
「http://my.example.com」のスクリプトは、動的に「http://other.example.com」を開けますが、このコンテンツ内にアクセスする事はできません。
 
■クロスサイトメッセージングを行う
 
クロスサイト間で連携するには、Web Messaging の機能を使用します。
 
異なるオリジン下のコンテンツ同士で、相互にオブジェクトを送受信する事ができます。
 

■ Web Messaging に対応しているか調べる

 
Web Messaging に対応しているか調べるには、window.postMessage が真であるか比較します。
 
Web Messaging に対応しているか調べる

// Web Messaging に対応している
if(window.postMessage){

	alert("Web Messaging に対応している");

}else{

	alert("Web Messaging に対応していない");

}
 
 
■Internet Explorer での対応について
 
Internet Explorer 7 以前では、対応していません。
 
バージョンによっては、一部の機能が未対応です。
 
こちらで解説しています。
 


 

基本的なメッセージングについて

 
 


■メッセージを受信する

 
■メッセージを受信するイベント
 
メッセージを受信するには、onmessage イベントを使用します。
 
デフォルトの状態で、最大のセキュリティリスクが発生する事に注意して下さい。
 
メッセージの受信側に制限はありません。すべてのメッセージを受け入れます。
 
登録したコールバック関数の引数から、MessageEvent オブジェクトが得られます。
 
■ MessageEvent について
 
MessageEvent オブジェクトには、以下のプロパティがあります。
 
プロパティ名説明
data*送信者から送られたデータを取得する。
originString送信者のオリジンを取得する。
sourceWindowProxy送信者の Window オブジェクトを取得する。
portsArray配列を取得する。中身は MessagePort オブジェクト。
lastEventIdStringLast-Event-ID リクエストヘッダの値を取得する?(Server-Sent Events 用)
 
■セキュリティについて (origin プロパティ)
 
送信者の生成元(オリジン)を取得するには、origin プロパティを使用します。
 
オリジンを取得して、信頼できる送信者であるか調べます。
 
不特定の送信者だった場合、拒絶するようにします。
 
■使用例
 
メッセージを受信する(この例では、http://sub.example.com のみ信頼し、それ以外を拒絶している)

// Web Messaging に対応している
if(window.postMessage){

	// ------------------------------------------------------------
	// 信頼するオリジン
	// ------------------------------------------------------------
	var origin_allow = "http://sub.example.com";

	// ------------------------------------------------------------
	// メッセージ受信時に実行されるコールバック関数
	// ------------------------------------------------------------
	var WindowMessageHandler = function (e) {

		// ------------------------------------------------------------
		// 信頼できる送信者か調べる
		// ------------------------------------------------------------
		if(e.origin != origin_allow) return;

		// ------------------------------------------------------------
		// 受信処理
		// ------------------------------------------------------------
		// 出力テスト(送信者から送られたデータ)
		console.log(e.data);

	};

	// ------------------------------------------------------------
	// イベントのリッスンを開始する
	// ------------------------------------------------------------
	// イベントリスナーに対応している
	if(window.addEventListener){

		// メッセージ受信時に実行されるイベント
		window.addEventListener("message" , WindowMessageHandler);

	// アタッチイベントに対応している
	}else if(window.attachEvent){

		// メッセージ受信時に実行されるイベント
		window.attachEvent("onmessage" , WindowMessageHandler);

	}

}
 

■メッセージを送信する

 
■相手の Window オブジェクトを取得する
 
送信先である、相手の Window オブジェクトを入手する必要があります。
 
任意の Window オブジェクトを取得する方法については、こちらで解説しています。
 
■メッセージを送信する
 
メッセージを送信するには、postMessage() メソッドを使用します。
 
相手の Window オブジェクトを使って呼び出します。
 
Window.postMessage( 送信データ , "相手のオリジン" , [譲渡データ] ) :Void
第01引数 *送信データを指定する。
第02引数 String送信を許可する相手のオリジンを指定する。
第03引数(略可)ArrayTransferable なオブジェクトを配列に格納して指定する。MessagePort などが該当。
戻り値 Voidなし。
 
■第01引数 (送信データ)
 
送信したいデータを指定します。
 
オブジェクトを指定した場合、複製されます。
 
Internet Explorer 9 以前では、文字列型に変換されます。
 
オブジェクトを指定したい場合は、JSON を使って変換します。
 
■第02引数 (相手のオリジン)
 
送信を許可する、相手のオリジンを指定します。
 
実際に送信に成功するのは、ここで指定したオリジンのみです。
 
相手ウィンドウには、同じページが表示され続けているとは限りません。
 
ユーザー操作によって、想定外の未知のページに変化している可能性があります。
 
以下の記号の指定も可能です。
 
指定文字列説明
"/"自身と同一のオリジンである場合のみ、送信を許可する。(IE8 では未対応)
"*"すべてのサイトに対して、送信を許可する。(最大のセキュリティリスク)
 
■第03引数 (譲渡データ)
 
Transferable なオブジェクトを、配列に格納して指定します。
 
MessagePortArrayBuffer オブジェクトなどが該当します。
 
ここで指定したオブジェクトは、所有権が相手に譲渡されます。
 
自身からは、アクセス不可能になり、再利用もできません。
 
■大容量のデータを譲渡する
 
一部のブラウザでは、 ArrayBuffer オブジェクトなどの譲渡が可能です。
 
大容量のデータを、複製せずに、相手に渡したい場合に便利です。
 
譲渡するデータは、第01引数と第03引数の両方に含める必要があります。
 
第01引数にのみ指定した場合、データは複製されます。
 

■メッセージを返信する

 
■相手の Window オブジェクトを取得する (source プロパティ)
 
送信者の Window オブジェクトを取得するには、source プロパティを使用します。
 
■メッセージを返信する
 
相手の Window オブジェクトを使って、postMessage() メソッドを呼び出します。
 
メッセージを返信する(この例では、http://sub.example.com のみ信頼し、それ以外を拒絶している)

// Web Messaging に対応している
if(window.postMessage){

	// ------------------------------------------------------------
	// 信頼するオリジン
	// ------------------------------------------------------------
	var origin_allow = "http://sub.example.com";

	// ------------------------------------------------------------
	// メッセージ受信時に実行されるコールバック関数
	// ------------------------------------------------------------
	var WindowMessageHandler = function (e) {

		// ------------------------------------------------------------
		// 信頼できる送信者か調べる
		// ------------------------------------------------------------
		if(e.origin != origin_allow) return;

		// ------------------------------------------------------------
		// 相手の Window オブジェクトを取得する
		// ------------------------------------------------------------
		var window_target = e.source;

		// ------------------------------------------------------------
		// 返信用オブジェクト
		// ------------------------------------------------------------
		var receive_obj = {
			message:"返信テスト",
			param:{}
		};

		// ------------------------------------------------------------
		// 返信する
		// ------------------------------------------------------------
		window_target.postMessage ( JSON.stringify(receive_obj) , origin_allow );

	};

	// ------------------------------------------------------------
	// イベントのリッスンを開始する
	// ------------------------------------------------------------
	if(window.addEventListener){
		window.addEventListener("message" , WindowMessageHandler);
	}else if(window.attachEvent){
		window.attachEvent("onmessage" , WindowMessageHandler);
	}

}
 

■メッセージの送受信例 (IFRAME 要素内)

 
親側のコンテンツを "http://my.com/aaa.html" とします。
 
子側のコンテンツを "http://other.com/bbb.html" とします。
 
■ http://my.com 側の処理について
 
インラインフレーム内に「http://other.com/bbb.html」を開き、送受信処理を行う

<html>
  <body>

    <fieldset style="padding:10px; margin-bottom:20px; background:#fee;" >
      <legend>自身のコンテンツ</legend>
      受信<br>
      <textarea id="input_result" style="width:100%; height:100px; margin:0px 0px 20px 0px;" ></textarea><br>
      送信<br>
      <input type="text"   id="input_message" style="width:100%; margin:0px 0px 10px 0px;" value="送信テスト" ><br>
      <input type="button" id="input_post"    style="width:100%; height:50px; margin:0px;" value="送信" >
    </fieldset>

    <fieldset style="padding:10px; margin-bottom:20px; background:#eef;" >
      <legend>相手のコンテンツ (インラインフレーム)</legend>
      <iframe id="iframe_target" src="http://other.com/bbb.html" style="width:100%; height:400px; background:#fff;" ></iframe>
    </fieldset>

    <script type="text/javascript">
    <!--

	// 信頼するオリジン
	var origin_allow = "http://other.com";

	// ------------------------------------------------------------
	// 各要素を取得
	// ------------------------------------------------------------
	var element_result  = document.getElementById("input_result");
	var element_message = document.getElementById("input_message");
	var element_post    = document.getElementById("input_post");
	var iframe_target   = document.getElementById("iframe_target");

	// ------------------------------------------------------------
	// メッセージ受信時に実行されるコールバック関数
	// ------------------------------------------------------------
	var WindowMessageHandler = function (e) {

		// 出力テスト
		element_result.value = "timeStamp:" + e.timeStamp + " origin:\"" + e.origin + "\"\n\n" + element_result.value;

		// ------------------------------------------------------------
		// 信頼できる送信者か調べる
		// ------------------------------------------------------------
		if(e.origin != origin_allow) return;

		// ------------------------------------------------------------
		// 受信処理
		// ------------------------------------------------------------
		// 受信データを取得
		var request_obj = JSON.parse(e.data);

		// 受信データを出力
		element_result.value = "data:" + JSON.stringify(request_obj) + "\n" + element_result.value;
	};

	// ------------------------------------------------------------
	// イベントのリッスンを開始する
	// ------------------------------------------------------------
	if(window.addEventListener){
		window.addEventListener("message" , WindowMessageHandler);
	}else if(window.attachEvent){
		window.attachEvent("onmessage" , WindowMessageHandler);
	}

	// ------------------------------------------------------------
	// 送信ボタンをクリックした時に実行されるイベント
	// ------------------------------------------------------------
	element_post.onclick = function (e){

		// ------------------------------------------------------------
		// インラインフレーム内の Window オブジェクトを取得
		// ------------------------------------------------------------
		var window_target  = iframe_target.contentWindow;

		// ------------------------------------------------------------
		// 送信用オブジェクト
		// ------------------------------------------------------------
		var request_obj = {
			message:element_message.value,
			param:{}
		};

		// ------------------------------------------------------------
		// 相手に送信する
		// ------------------------------------------------------------
		window_target.postMessage( JSON.stringify(request_obj) , origin_allow );

	};

    //-->
    </script>

  </body>
</html>
 
■ http://other.com 側の処理について
 
受信検出した相手に対して、送受信処理を行う(この例では、http://my.com のみ信頼し、それ以外を拒絶している)

<html>
  <body>

    <fieldset style="padding:10px; margin-bottom:20px; background:#eef;" >
      <legend>自身のコンテンツ</legend>
      受信<br>
      <textarea id="input_result" style="width:100%; height:100px; margin:0px 0px 20px 0px;" ></textarea><br>
      送信<br>
      <input type="text"   id="input_message" style="width:100%; margin:0px 0px 10px 0px;" value="送信テスト" ><br>
      <input type="button" id="input_post"    style="width:100%; height:50px; margin:0px;" value="送信" >
    </fieldset>

    <script type="text/javascript">
    <!--

	// 相手の Window オブジェクト
	var window_target = null;

	// 信頼するオリジン
	var origin_allow = "http://my.com";

	// ------------------------------------------------------------
	// 各要素を取得
	// ------------------------------------------------------------
	var element_result  = document.getElementById("input_result");
	var element_message = document.getElementById("input_message");
	var element_post    = document.getElementById("input_post");

	// ------------------------------------------------------------
	// 親のウィンドウを取得する
	// ------------------------------------------------------------
	if(window.parent !== window.self){
		window_target = window.parent;
	}

	// ------------------------------------------------------------
	// メッセージ受信時に実行されるコールバック関数
	// ------------------------------------------------------------
	var WindowMessageHandler = function (e) {

		// 出力テスト
		element_result.value = "timeStamp:" + e.timeStamp + " origin:\"" + e.origin + "\"\n\n" + element_result.value;

		// ------------------------------------------------------------
		// 信頼できる送信者か調べる
		// ------------------------------------------------------------
		if(e.origin != origin_allow) return;

		// ------------------------------------------------------------
		// 受信処理
		// ------------------------------------------------------------
		// 相手の Window オブジェクトを取得する
		window_target = e.source;

		// 受信データを取得
		var request_obj = JSON.parse(e.data);

		// 受信データを出力
		element_result.value = "data:" + JSON.stringify(request_obj) + "\n" + element_result.value;
	};

	// ------------------------------------------------------------
	// イベントのリッスンを開始する
	// ------------------------------------------------------------
	if(window.addEventListener){
		window.addEventListener("message" , WindowMessageHandler);
	}else if(window.attachEvent){
		window.attachEvent("onmessage" , WindowMessageHandler);
	}

	// ------------------------------------------------------------
	// 送信ボタンをクリックした時に実行されるイベント
	// ------------------------------------------------------------
	element_post.onclick = function (e){
		if(!(window_target)) return;

		// ------------------------------------------------------------
		// 送信用オブジェクト
		// ------------------------------------------------------------
		var request_obj = {
			message:element_message.value,
			param:{}
		};

		// ------------------------------------------------------------
		// 相手に送信する
		// ------------------------------------------------------------
		window_target.postMessage( JSON.stringify(request_obj) , origin_allow );

	};
    //-->
    </script>

  </body>
</html>
 

■メッセージの送受信例 (別ウィンドウ)

 
親側のコンテンツを "http://my.com/aaa.html" とします。
 
子側のコンテンツを "http://other.com/bbb.html" とします。
 
■ http://my.com 側の処理について
 
window.open() メソッドを使って「http://other.com/bbb.html」を開き、送受信処理を行う

<html>
  <body>

    <fieldset style="padding:10px; margin-bottom:20px; background:#fee;" >
      <legend>自身のコンテンツ</legend>
      受信<br>
      <textarea id="input_result" style="width:100%; height:100px; margin:0px 0px 20px 0px;" ></textarea><br>
      送信<br>
      <input type="text"   id="input_message" style="width:100%; margin:0px 0px 10px 0px;" value="送信テスト" ><br>
      <input type="button" id="input_post"    style="width:100%; height:50px; margin:0px;" value="送信" >
    </fieldset>

    <fieldset style="padding:10px; margin-bottom:20px; background:#eef;" >
      <legend>相手のコンテンツ (別ウィンドウ)</legend>
      <input type="button" id="input_open" style="width:100%; height:50px; margin:0px;" value="相手ウィンドウを開く" ><br>
    </fieldset>

    <script type="text/javascript">
    <!--

	// 相手の Window オブジェクト
	var window_target = null;

	// 信頼するオリジン
	var origin_allow = "http://other.com";

	// ------------------------------------------------------------
	// 各要素を取得
	// ------------------------------------------------------------
	var element_result  = document.getElementById("input_result");
	var element_message = document.getElementById("input_message");
	var element_post    = document.getElementById("input_post");
	var element_open    = document.getElementById("input_open");

	// ------------------------------------------------------------
	// メッセージ受信時に実行されるコールバック関数
	// ------------------------------------------------------------
	var WindowMessageHandler = function (e) {

		// 出力テスト
		element_result.value = "timeStamp:" + e.timeStamp + " origin:\"" + e.origin + "\"\n\n" + element_result.value;

		// ------------------------------------------------------------
		// 信頼できる送信者か調べる
		// ------------------------------------------------------------
		if(e.origin != origin_allow) return;

		// ------------------------------------------------------------
		// 受信処理
		// ------------------------------------------------------------
		// 受信データを取得
		var request_obj = e.data;

		// 受信データを出力
		element_result.value = "data:" + JSON.stringify(request_obj) + "\n" + element_result.value;
	};

	// ------------------------------------------------------------
	// イベントのリッスンを開始する
	// ------------------------------------------------------------
	if(window.addEventListener){
		window.addEventListener("message" , WindowMessageHandler);
	}else if(window.attachEvent){
		window.attachEvent("onmessage" , WindowMessageHandler);
	}

	// ------------------------------------------------------------
	// 送信ボタンをクリックした時に実行されるイベント
	// ------------------------------------------------------------
	element_post.onclick = function (e){
		if(!(window_target)) return;

		// ------------------------------------------------------------
		// 送信用オブジェクト
		// ------------------------------------------------------------
		var request_obj = {
			message:element_message.value,
			param:{}
		};

		// ------------------------------------------------------------
		// 相手に送信する
		// ------------------------------------------------------------
		window_target.postMessage( request_obj , origin_allow );

	};

	// ------------------------------------------------------------
	// 開くボタンをクリックした時に実行されるイベント
	// ------------------------------------------------------------
	element_open.onclick = function (e){
		if(window_target && !(window_target.closed)) return;

		// ------------------------------------------------------------
		// ウィンドウを作成する
		// ------------------------------------------------------------
		window_target = window.open(origin_allow + "/bbb.html" , "_blank" , "width=800,height=600");

	};
    //-->
    </script>

  </body>
</html>
 
■ http://other.com 側の処理について
 
外部から開かれた相手に対して、送受信処理を行う(この例では、http://my.com のみ信頼し、それ以外を拒絶している)

<html>
  <body>

    <fieldset style="padding:10px; margin-bottom:20px; background:#eef;" >
      <legend>自身のコンテンツ</legend>
      受信<br>
      <textarea id="input_result" style="width:100%; height:100px; margin:0px 0px 20px 0px;" ></textarea><br>
      送信<br>
      <input type="text"   id="input_message" style="width:100%; margin:0px 0px 10px 0px;" value="送信テスト" ><br>
      <input type="button" id="input_post"    style="width:100%; height:50px; margin:0px;" value="送信" >
    </fieldset>

    <script type="text/javascript">
    <!--

	// 相手の Window オブジェクト
	var window_target = null;

	// 信頼するオリジン
	var origin_allow = "http://my.com";

	// ------------------------------------------------------------
	// 各要素を取得
	// ------------------------------------------------------------
	var element_result  = document.getElementById("input_result");
	var element_message = document.getElementById("input_message");
	var element_post    = document.getElementById("input_post");

	// ------------------------------------------------------------
	// 生成主ウィンドウを取得する(無ければ null 値)
	// ------------------------------------------------------------
	window_target = window.opener;

	// ------------------------------------------------------------
	// メッセージ受信時に実行されるコールバック関数
	// ------------------------------------------------------------
	var WindowMessageHandler = function (e) {

		// 出力テスト
		element_result.value = "timeStamp:" + e.timeStamp + " origin:\"" + e.origin + "\"\n\n" + element_result.value;

		// ------------------------------------------------------------
		// 信頼できる送信者か調べる
		// ------------------------------------------------------------
		if(e.origin != origin_allow) return;

		// ------------------------------------------------------------
		// 受信処理
		// ------------------------------------------------------------
		// 相手の Window オブジェクトを取得する
		window_target = e.source;

		// 受信データを取得
		var request_obj = e.data;

		// 受信データを出力
		element_result.value = "data:" + JSON.stringify(request_obj) + "\n" + element_result.value;
	};

	// ------------------------------------------------------------
	// イベントのリッスンを開始する
	// ------------------------------------------------------------
	if(window.addEventListener){
		window.addEventListener("message" , WindowMessageHandler);
	}else if(window.attachEvent){
		window.attachEvent("onmessage" , WindowMessageHandler);
	}

	// ------------------------------------------------------------
	// 送信ボタンをクリックした時に実行されるイベント
	// ------------------------------------------------------------
	element_post.onclick = function (e){
		if(!(window_target)) return;

		// ------------------------------------------------------------
		// 送信用オブジェクト
		// ------------------------------------------------------------
		var request_obj = {
			message:element_message.value,
			param:{}
		};

		// ------------------------------------------------------------
		// 相手に送信する
		// ------------------------------------------------------------
		window_target.postMessage( request_obj , origin_allow );

	};
    //-->
    </script>

  </body>
</html>
 

■ Internet Explorer での動作について

 
■ IFRAME 要素内との通信について
 
IFRAME 要素内との通信は、Internet Explorer 8 以降から対応しています。
 
別オリジン間の通信も可能です。
 
■別ウィンドウとの通信について
 
別ウィンドウとの通信は、Internet Explorer 10 以降から対応しています。
 
別オリジン間の通信は、Internet Explorer 11 以降から対応しています。
 


 

チャンネルメッセージングについて

 
 


■チャンネルメッセージングについて

 
チャンネルメッセージングを使用すると、独占的な通信経路を構築する事ができます。
 
1つだけでなく、複数のチャンネルを構築する事もできます。
 
どちらか片方がロストした場合、通信経路は自動的に閉じられます。
 
これにより、相手が別の Web ページに変化しても安全です。
 
相手のオリジンの確認は、最初の一度だけで済みます。
 
Internet Explorer 9 以前では、対応していません。
 
Google Chrome 45 の時点では、譲渡送信は動作しないようです。
 
試みた場合、data プロパティから null 値が得られ、正常動作しなくなります。
 

■メッセージチャンネルを構築する

 
■ MessageChannel オブジェクトを作成する
 
new 演算子を使って、MessageChannel オブジェクトを作成します。
 
複数のチャンネルを構築したい場合は、必要な数だけ生成します。
 
MessageChannel オブジェクトを作成する

// MessageChannel に対応している
if(window.MessageChannel){

	// MessageChannel オブジェクトを作成する
	var message_channel = new MessageChannel();

	// 出力テスト
	console.log(message_channel);

}
 
■ MessageChannel オブジェクトについて
 
中には、2つの MessagePort オブジェクトが格納されています。
 
どちらか片方を自分用に確保し、もう片方は相手に送信します。
 
ここでは、port1 を、自分が使用するものとします。
 
プロパティ 解説
port1 MessagePort MessagePort オブジェクトが得られる
port2 MessagePort MessagePort オブジェクトが得られる
 
■ MessagePort オブジェクトを相手に送信する(発動側の処理)
 
相手に MessagePort オブジェクトを渡すには、postMessage() メソッドを使用します。
 
MessagePort オブジェクトを配列に格納して、第03引数に渡します。
 
MessagePort オブジェクトは、Transferable なオブジェクトです。
 
送信すると、所有権が相手に譲渡されます。
 
■相手から MessagePort オブジェクトを受け取る(受動側の処理)
 
相手から MessagePort オブジェクトを受け取るには、onmessage イベントを使用します。
 
ports プロパティから、MessagePort オブジェクトのリストが得られます。
 

■チャンネル経由で、メッセージを受信する

 
■メッセージを受信するイベント
 
メッセージを受信するには、onmessage イベントを使用します。
 
リスナーを、自身の MessagePort オブジェクトに登録します。
 
登録したコールバック関数の引数から、MessageEvent オブジェクトが得られます。
 
チャンネルメッセージングでは、以下の情報が取得できます。
 
プロパティ名説明
data*送信者から送られたデータを取得する。
portsArray配列を取得する。中身は MessagePort オブジェクト。
 
■受信を開始する
 
受信を開始するには、start() メソッドを使用します。
 
onmessage プロパティを使用した場合は、自動的に開始されます。
 
受信を開始していない場合、メッセージはキューに蓄積されます。
 
受信を開始すると、相手からのメッセージが、まとめて得られます。
 

■チャンネル経由で、メッセージを送信する

 
■メッセージを送信する
 
メッセージを送信するには、postMessage() メソッドを使用します。
 
自身の MessagePort オブジェクトから呼び出します。
 
MessagePort.postMessage( 送信データ , [譲渡データ] ) :Void
第01引数 *送信データを指定する。
第02引数(略可)ArrayTransferable なオブジェクトを配列に格納して指定する。MessagePort などが該当。
戻り値 Voidなし。
 
■第01引数 (送信データ)
 
送信したいデータを指定します。
 
オブジェクトを指定した場合、複製されます。
 
■第02引数 (譲渡データ)
 
Transferable なオブジェクトを、配列に格納して指定します。
 
MessagePortArrayBuffer オブジェクトなどが該当します。
 
ここで指定したオブジェクトは、所有権が相手に譲渡されます。
 
自身からは、アクセス不可能になり、再利用もできません。
 
■大容量のデータを譲渡する
 
一部のブラウザでは、 ArrayBuffer オブジェクトなどの譲渡が可能です。
 
大容量のデータを、複製せずに、相手に渡したい場合に便利です。
 
譲渡するデータは、第01引数と第02引数の両方に含める必要があります。
 
第01引数にのみ指定した場合、データは複製されます。
 

■メッセージチャンネルを終了する

 
メッセージチャンネルを終了するには、close() メソッドを使用します。
 
自身や相手がアンロードされた場合、メッセージチャンネルは、自動的に終了します。
 

■チャンネルメッセージングの送受信例 (IFRAME 要素内)

 
親側のコンテンツを "http://my.com/aaa.html" とします。
 
子側のコンテンツを "http://other.com/bbb.html" とします。
 
この例では、子側からリクエストを開始します。
 
■ http://my.com 側の処理について
 
インラインフレーム内に「http://other.com/bbb.html」を開き、子からリクエストを待つ

<html>
  <body>

    <fieldset style="padding:10px; margin-bottom:20px; background:#fee;" >
      <legend>自身のコンテンツ</legend>
      受信<br>
      <textarea id="input_result" style="width:100%; height:100px; margin:0px 0px 20px 0px;" ></textarea><br>
      送信<br>
      <input type="text"   id="input_message" style="width:100%; margin:0px 0px 10px 0px;" value="送信テスト" ><br>
      <input type="button" id="input_post"    style="width:100%; height:50px; margin:0px;" value="送信" >
    </fieldset>

    <fieldset style="padding:10px; margin-bottom:20px; background:#eef;" >
      <legend>相手のコンテンツ (インラインフレーム)</legend>
      <input type="button" id="input_add" style="width:100%; height:50px; margin:0px;" value="インラインフレームを追加" >
    </fieldset>

    <script type="text/javascript">
    <!--

	// 匿名関数を即時実行
	(function(){

		// MessagePort オブジェクトのリスト
		var message_port_list = new Array();

		// 信頼するオリジン
		var origin_allow = "http://other.com";

		// ------------------------------------------------------------
		// MessageChannel に対応しているか調べる
		// ------------------------------------------------------------
		if(!(window.MessageChannel)) return;

		// ------------------------------------------------------------
		// 各要素を取得
		// ------------------------------------------------------------
		var element_result  = document.getElementById("input_result");
		var element_message = document.getElementById("input_message");
		var element_post    = document.getElementById("input_post");
		var element_add     = document.getElementById("input_add");

		// ------------------------------------------------------------
		// 基本的なメッセージ受信時に実行されるコールバック関数
		// ------------------------------------------------------------
		var WindowMessageHandler = function (e) {

			// ------------------------------------------------------------
			// 信頼できる送信者か調べる
			// ------------------------------------------------------------
			if(e.origin != origin_allow) return;

			// ------------------------------------------------------------
			// MessagePort オブジェクトが送られてきたか調べる
			// ------------------------------------------------------------
			var i;
			var num = e.ports.length;
			for(i=0;i < num;i++){

				(function(){

					// ------------------------------------------------------------
					// MessagePort オブジェクトを取得
					// ------------------------------------------------------------
					var message_port = e.ports[i];

					// ------------------------------------------------------------
					// チャンネル経由のメッセージ受信時に実行されるイベント
					// ------------------------------------------------------------
					message_port.onmessage = function (e) {

						// 出力テスト
						element_result.value = "timeStamp:" + e.timeStamp + " origin:\"" + e.origin + "\"\n\n" + element_result.value;

						// ------------------------------------------------------------
						// 受信処理
						// ------------------------------------------------------------
						// 受信データを取得
						var request_obj = e.data;

						// 受信データを出力
						element_result.value = "data:" + JSON.stringify(request_obj) + "\n" + element_result.value;
					};

					// ------------------------------------------------------------
					// チャンネル経由のメッセージ受信を開始する
					// ------------------------------------------------------------
					message_port.start();

					// リストに登録
					message_port_list.push(message_port);

				})();
			}
		};

		// ------------------------------------------------------------
		// イベントのリッスンを開始する
		// ------------------------------------------------------------
		if(window.addEventListener){
			window.addEventListener("message" , WindowMessageHandler);
		}else if(window.attachEvent){
			window.attachEvent("onmessage" , WindowMessageHandler);
		}

		// ------------------------------------------------------------
		// 送信ボタンをクリックした時に実行されるイベント
		// ------------------------------------------------------------
		element_post.onclick = function (e){

			// ------------------------------------------------------------
			// 全員に送信する
			// ------------------------------------------------------------
			var i;
			var num = message_port_list.length;
			for(i=0;i < num;i++){
				var message_port = message_port_list[i];

				// ------------------------------------------------------------
				// 送信用オブジェクト
				// ------------------------------------------------------------
				var request_obj = {
					message:element_message.value,
					param:{}
				};

				// ------------------------------------------------------------
				// 相手に送信する
				// ------------------------------------------------------------
				message_port.postMessage( request_obj );
			}

		};

		// ------------------------------------------------------------
		// 追加ボタンをクリックした時に実行されるイベント
		// ------------------------------------------------------------
		element_add.onclick = function (e){

			// HTMLIframeElement オブジェクトを作成
			var iframe = document.createElement("iframe");

			// インラインスタイルを設定
			iframe.style.cssText = "width:400px; height:400px; margin-top:10px; margin-right:10px; border-width:5px; background:#fff;";

			// URL アドレスを設定
			iframe.src = origin_allow + "/bbb.html";

			// ノードリストに登録
			element_add.parentNode.appendChild(iframe);

		};

	})();

    //-->
    </script>

  </body>
</html>
 
■ http://other.com 側の処理について
 
1つ上の親に対して、チャンネルメッセージングを行う(この例では、http://my.com のみ信頼し、それ以外を拒絶している)

<html>
  <body>

    <fieldset style="padding:10px; margin-bottom:20px; background:#eef;" >
      <legend>自身のコンテンツ</legend>
      受信<br>
      <textarea id="input_result" style="width:100%; height:100px; margin:0px 0px 20px 0px;" ></textarea><br>
      送信<br>
      <input type="text"   id="input_message" style="width:100%; margin:0px 0px 10px 0px;" value="送信テスト" ><br>
      <input type="button" id="input_post"    style="width:100%; height:50px; margin:0px;" value="送信" >
    </fieldset>

    <script type="text/javascript">
    <!--

	// 匿名関数を即時実行
	(function(){

		// 自身用の MessagePort オブジェクト
		var message_port = null;

		// 信頼するオリジン
		var origin_allow = "http://my.com";

		// ------------------------------------------------------------
		// MessageChannel に対応しているか調べる
		// ------------------------------------------------------------
		if(!(window.MessageChannel)) return;

		// ------------------------------------------------------------
		// 各要素を取得
		// ------------------------------------------------------------
		var element_result  = document.getElementById("input_result");
		var element_message = document.getElementById("input_message");
		var element_post    = document.getElementById("input_post");

		// ------------------------------------------------------------
		// MessageChannel オブジェクトを作成
		// ------------------------------------------------------------
		var message_channel  = new MessageChannel();

		// ------------------------------------------------------------
		// 自身用の MessagePort オブジェクトを確保
		// ------------------------------------------------------------
		message_port = message_channel.port1;

		// ------------------------------------------------------------
		// チャンネル経由のメッセージ受信時に実行されるイベント
		// ------------------------------------------------------------
		message_port.onmessage = function (e) {

			// 出力テスト
			element_result.value = "timeStamp:" + e.timeStamp + " origin:\"" + e.origin + "\"\n\n" + element_result.value;

			// ------------------------------------------------------------
			// 受信処理
			// ------------------------------------------------------------
			// 受信データを取得
			var request_obj = e.data;

			// 受信データを出力
			element_result.value = "data:" + JSON.stringify(request_obj) + "\n" + element_result.value;
		};

		// ------------------------------------------------------------
		// チャンネル経由のメッセージ受信を開始する
		// ------------------------------------------------------------
		message_port.start();

		// ------------------------------------------------------------
		// 送信ボタンをクリックした時に実行されるイベント
		// ------------------------------------------------------------
		element_post.onclick = function (e){

			// ------------------------------------------------------------
			// 送信用オブジェクト
			// ------------------------------------------------------------
			var request_obj = {
				message:element_message.value,
				param:{}
			};

			// ------------------------------------------------------------
			// 相手に送信する
			// ------------------------------------------------------------
			message_port.postMessage( request_obj );

		};

		// ------------------------------------------------------------
		// 読み込み完了時に実行されるイベント
		// ------------------------------------------------------------
		window.onload = function (e){

			// ------------------------------------------------------------
			// 親のウィンドウを取得する
			// ------------------------------------------------------------
			if(window.parent === window.self) return;
			var window_target = window.parent;

			// ------------------------------------------------------------
			// 送信用オブジェクト
			// ------------------------------------------------------------
			var request_obj = {command:"requestChannelMessaging"};

			try{
				// ------------------------------------------------------------
				// 相手に MessagePort オブジェクトを送信する
				// ------------------------------------------------------------
				window_target.postMessage( request_obj , origin_allow , [message_channel.port2] );

			}catch(e){
				// ------------------------------------------------------------
				// Safari 5 の場合 (第02引数と第03引数を入れ替える)
				// ------------------------------------------------------------
				// window_target.postMessage( request_obj , [message_channel.port2] , origin_allow );
			}

		};

	})();

    //-->
    </script>

  </body>
</html>
 

■チャンネルメッセージングの送受信例 (別ウィンドウ)

 
親側のコンテンツを "http://my.com/aaa.html" とします。
 
子側のコンテンツを "http://other.com/bbb.html" とします。
 
この例では、子側からリクエストを開始します。
 
■ http://my.com 側の処理について
 
window.open() メソッドを使って「http://other.com/bbb.html」を開き、子からリクエストを待つ

<html>
  <body>

    <fieldset style="padding:10px; margin-bottom:20px; background:#fee;" >
      <legend>自身のコンテンツ</legend>
      受信<br>
      <textarea id="input_result" style="width:100%; height:100px; margin:0px 0px 20px 0px;" ></textarea><br>
      送信<br>
      <input type="text"   id="input_message" style="width:100%; margin:0px 0px 10px 0px;" value="送信テスト" ><br>
      <input type="button" id="input_post"    style="width:100%; height:50px; margin:0px;" value="送信" >
    </fieldset>

    <fieldset style="padding:10px; margin-bottom:20px; background:#eef;" >
      <legend>相手のコンテンツ (別ウィンドウ)</legend>
      <input type="button" id="input_open" style="width:100%; height:50px; margin:0px;" value="相手ウィンドウを開く" ><br>
    </fieldset>

    <script type="text/javascript">
    <!--

	// 匿名関数を即時実行
	(function(){

		// MessagePort オブジェクトのリスト
		var message_port_list = new Array();

		// 信頼するオリジン
		var origin_allow = "http://other.com";

		// ------------------------------------------------------------
		// MessageChannel に対応しているか調べる
		// ------------------------------------------------------------
		if(!(window.MessageChannel)) return;

		// ------------------------------------------------------------
		// 各要素を取得
		// ------------------------------------------------------------
		var element_result  = document.getElementById("input_result");
		var element_message = document.getElementById("input_message");
		var element_post    = document.getElementById("input_post");
		var element_open    = document.getElementById("input_open");

		// ------------------------------------------------------------
		// 基本的なメッセージ受信時に実行されるコールバック関数
		// ------------------------------------------------------------
		var WindowMessageHandler = function (e) {

			// ------------------------------------------------------------
			// 信頼できる送信者か調べる
			// ------------------------------------------------------------
			if(e.origin != origin_allow) return;

			// ------------------------------------------------------------
			// MessagePort オブジェクトが送られてきたか調べる
			// ------------------------------------------------------------
			var i;
			var num = e.ports.length;
			for(i=0;i < num;i++){

				(function(){

					// ------------------------------------------------------------
					// MessagePort オブジェクトを取得
					// ------------------------------------------------------------
					var message_port = e.ports[i];

					// ------------------------------------------------------------
					// チャンネル経由のメッセージ受信時に実行されるイベント
					// ------------------------------------------------------------
					message_port.onmessage = function (e) {

						// 出力テスト
						element_result.value = "timeStamp:" + e.timeStamp + " origin:\"" + e.origin + "\"\n\n" + element_result.value;

						// ------------------------------------------------------------
						// 受信処理
						// ------------------------------------------------------------
						// 受信データを取得
						var request_obj = e.data;

						// 受信データを出力
						element_result.value = "data:" + JSON.stringify(request_obj) + "\n" + element_result.value;
					};

					// ------------------------------------------------------------
					// チャンネル経由のメッセージ受信を開始する
					// ------------------------------------------------------------
					message_port.start();

					// リストに登録
					message_port_list.push(message_port);

				})();
			}
		};

		// ------------------------------------------------------------
		// イベントのリッスンを開始する
		// ------------------------------------------------------------
		if(window.addEventListener){
			window.addEventListener("message" , WindowMessageHandler);
		}else if(window.attachEvent){
			window.attachEvent("onmessage" , WindowMessageHandler);
		}

		// ------------------------------------------------------------
		// 送信ボタンをクリックした時に実行されるイベント
		// ------------------------------------------------------------
		element_post.onclick = function (e){

			// ------------------------------------------------------------
			// 全員に送信する
			// ------------------------------------------------------------
			var i;
			var num = message_port_list.length;
			for(i=0;i < num;i++){
				var message_port = message_port_list[i];

				// ------------------------------------------------------------
				// 送信用オブジェクト
				// ------------------------------------------------------------
				var request_obj = {
					message:element_message.value,
					param:{}
				};

				// ------------------------------------------------------------
				// チャンネル経由で相手にメッセージを送信する
				// ------------------------------------------------------------
				message_port.postMessage( request_obj );
			}
		};

		// ------------------------------------------------------------
		// 開くボタンをクリックした時に実行されるイベント
		// ------------------------------------------------------------
		element_open.onclick = function (e){

			// ------------------------------------------------------------
			// ウィンドウを作成する
			// ------------------------------------------------------------
			window.open(origin_allow + "/bbb.html" , "_blank" , "width=800,height=600");

		};

	})();
    //-->
    </script>

  </body>
</html>
 
■ http://other.com 側の処理について
 
外部から開かれた相手に対して、チャンネルメッセージングを行う(この例では、http://my.com のみ信頼し、それ以外を拒絶している)

<html>
  <body>

    <fieldset style="padding:10px; margin-bottom:20px; background:#eef;" >
      <legend>自身のコンテンツ</legend>
      受信<br>
      <textarea id="input_result" style="width:100%; height:100px; margin:0px 0px 20px 0px;" ></textarea><br>
      送信<br>
      <input type="text"   id="input_message" style="width:100%; margin:0px 0px 10px 0px;" value="送信テスト" ><br>
      <input type="button" id="input_post"    style="width:100%; height:50px; margin:0px;" value="送信" >
    </fieldset>

    <script type="text/javascript">
    <!--

	// 匿名関数を即時実行
	(function(){

		// 自身用の MessagePort オブジェクト
		var message_port = null;

		// 信頼するオリジン
		var origin_allow = "http://my.com";

		// ------------------------------------------------------------
		// 各要素を取得
		// ------------------------------------------------------------
		var element_result  = document.getElementById("input_result");
		var element_message = document.getElementById("input_message");
		var element_post    = document.getElementById("input_post");

		// ------------------------------------------------------------
		// MessageChannel に対応しているか調べる
		// ------------------------------------------------------------
		if(!(window.MessageChannel)) return;

		// ------------------------------------------------------------
		// MessageChannel オブジェクトを作成
		// ------------------------------------------------------------
		var message_channel  = new MessageChannel();

		// ------------------------------------------------------------
		// 自身用の MessagePort オブジェクトを確保
		// ------------------------------------------------------------
		message_port = message_channel.port1;

		// ------------------------------------------------------------
		// チャンネル経由のメッセージ受信時に実行されるイベント
		// ------------------------------------------------------------
		message_port.onmessage = function (e) {

			// 出力テスト
			element_result.value = "timeStamp:" + e.timeStamp + " origin:\"" + e.origin + "\"\n\n" + element_result.value;

			// ------------------------------------------------------------
			// 受信処理
			// ------------------------------------------------------------
			// 受信データを取得
			var request_obj = e.data;

			// 受信データを出力
			element_result.value = "data:" + JSON.stringify(request_obj) + "\n" + element_result.value;
		};

		// ------------------------------------------------------------
		// チャンネル経由のメッセージ受信を開始する
		// ------------------------------------------------------------
		message_port.start();

		// ------------------------------------------------------------
		// 送信ボタンをクリックした時に実行されるイベント
		// ------------------------------------------------------------
		element_post.onclick = function (e){

			// ------------------------------------------------------------
			// 送信用オブジェクト
			// ------------------------------------------------------------
			var request_obj = {
				message:element_message.value,
				param:{}
			};

			// ------------------------------------------------------------
			// 相手に送信する
			// ------------------------------------------------------------
			message_port.postMessage( request_obj );

		};

		// ------------------------------------------------------------
		// 読み込み完了時に実行されるイベント
		// ------------------------------------------------------------
		window.onload = function (e){

			// ------------------------------------------------------------
			// 生成主ウィンドウを取得する
			// ------------------------------------------------------------
			var window_target = window.opener;
			if(!window_target) return;

			// ------------------------------------------------------------
			// 送信用オブジェクト
			// ------------------------------------------------------------
			var request_obj = {command:"requestChannelMessaging"};

			try{
				// ------------------------------------------------------------
				// 相手に MessagePort オブジェクトを送信する
				// ------------------------------------------------------------
				window_target.postMessage( request_obj , origin_allow , [message_channel.port2] );

			}catch(e){
				// ------------------------------------------------------------
				// Safari 5 の場合 (第02引数と第03引数を入れ替える)
				// ------------------------------------------------------------
				// window_target.postMessage( request_obj , [message_channel.port2] , origin_allow );
			}

		};

	})();
    //-->
    </script>

  </body>
</html>