postMessage
一般的に広く使われている、?
以降の文字列http://
というURLにアクセスするとquery_
の部分がサーバに送信されます。当然新規の通信が発生しますし、
<iframe src="http://example.com/" name="message">
http://example.com/#location.hash
postMessage登場以前
リスト1のname="message"
の部分はJavaScriptの変数window.#
以降、
postMessageの誕生
HTML5でpostMessageが導入されたことで、
window.postMessageは、安全にクロスドメイン通信を可能にするためのメソッドです。
と紹介されていますが、
クロスドメインのためのAPI設計
写真サービスhttp://
、http://
があると想定します。それぞれのサービスは別組織が運営していて、
ダメな例:パスワードを預かる
photo.
のユーザidとパスワードをblog.
が預かって、blog.
側のミスでパスワードが漏洩
ダメな例:JSONP
ブラウザから直接photo.
のデータを参照します。http://
というAPIを用意して、
- ログイン中のCookieを送ることでユーザを識別する
- JSONPもしくは、
CORS (Cross-Origin Resource Sharing) により許可されたXMLHttpRequestでリソースを取得する
こういったAPIを作ってしまうと、
APIを用意してJSONPで写真の一覧を返す方法についてもう少し深く、photo.
がblog.
をblog.
からのみ、
JSONPは呼び出し元を制限することが困難です。リファラを参照することで想定と異なるドメインから呼び出されたことを検出できますが、
良い例:OAuthを使う
初回アクセス時、photo.
にリダイレクトしてphoto.
がblog.
に対し、http://
に対するJSONPやクロスドメインXMLHttpRequestのリクエストに、
postMessageを使ったクロスドメイン通信
ここまで見てきたように、blog.
からphoto.
の中身はドメインが異なるため、photo.
ドメイン上でブログに貼り付けたい写真を選択し、blog.
ドメインに対して張り付けたい画像のURLをpostMessageで送信します。postMessageを使った呼び出し元の実装例
- ① windowを開く
- ② 呼び出し元を確認しつつ写真を選択する
- ③ 事前にアクセストークンを交換する
など、
- 外部でどんなサービスを使っているのか
- 誰としてログインしているのか
- 貼り付ける画像以外に、
ユーザがどんな画像を持っているのか
本来知る必要がない情報です。

<html>
<head><meta charset="utf-8">
</head>
<body>
<button onclick="run_selector()">写真を選択</button><br>
state<input id="state" size="100"><br>
result<input id="result" size="100"><br>
<script>
var photo_url = "http://photo.example.com/photo.html";
var photo_origin = "http://photo.example.com";
var timer;
function $(id){ return document.getElementById(id) }
window.onmessage = function(event){
console.log(event);
if (event.origin === photo_origin) {
clearInterval(timer);
var result = JSON.parse(event.data);
$("state").value = result.state;
$("result").value = result.result;
}
};
function run_selector(){
popup = window.open(photo_url, "",
"width=300,height=300");
timer = setInterval(function(){
popup.postMessage("select_photo", photo_origin);
}, 100);
}
</script>
</body>
</html>

<html>
<head><meta charset="utf-8"></head>
<body>
<p><span id="source"></span> が写真を求めています</p>
<input name="photo" type="checkbox" checked value="http://photo.example.com/1.jpg">写真1<br>
<input name="photo" type="checkbox" checked value="http://photo.example.com/2.jpg">写真2<br>
<input name="photo" type="checkbox" checked value="http://photo.example.com/3.jpg">写真3<br>
<input name="photo" type="checkbox" checked value="http://photo.example.com/4.jpg">写真4<br>
<button onclick="do_response({state:'選択しました', result: selected()});window.close()">許可</button>
<button onclick="do_response({state:'拒否されました'});window.close()">拒否</button>
<script>
var opener_origin = "";
function $(id){ return document.getElementById(id) }
function selected(){
var result = [];
var input = document.querySelectorAll("input");
for (var i=0; i < input.length; i++) {
if (input[i].checked) result.push(input[i].value);
}
return result;
}
window.onmessage = function(event){
$("source").innerHTML = event.origin;
opener_origin = event.origin;
do_response({ state: "準備中", result: "まだ選択されていません"}, opener_origin);
}
function do_response(res){
window.opener.postMessage(JSON.stringify(res), opener_origin);
}
</script>
</body></html>
OAuthを使って、
OAuth 2.0との比較
OAuth 2.
- サーバ側:有効なアクセストークンの管理
- クライアント側:取得したアクセストークンの管理
OAuthを使って、
対してpostMessageを使った方式のポイントは、photo.
は連携機能を許可済みのドメインの一覧をphoto.
のlocalStorageに保存しておくことができます。blog.