IFrameとFragment Identifier使ったクロスドメイン通信について

なぜかちょっと盛り上がり気味な記事

XhrIframeProxy(dojo) ○? △? 中? マウスクリック音有り
iframe内iframe ○? △? 中? マウスクリック音有り
http://d.hatena.ne.jp/nopnop/20080408/1207669947

この2つはFragment Identifierと多重IFrameを利用しているという点では同じなのかなあ。

正直、これらは何を内部でおこなっているか分かりにくいと思う。JSONPのような簡潔さはない。

説明を試みてみる。理解するためにまず押さえておくことがいくつかある。

まずひとつ目に、フレーム(ウィンドウ)に含まれるドキュメントを示す location の値はそのフレーム外部から書き換えることができる。こんなかんじ。

<iframe  id="ifr" src="http://www.example.com/" ></iframe>
<script type="text/javascript">
var ifr = document.getElementByid('ifr');
ifr.contentWindow.location.replace('http://example.co.jp/');
</script>

上記のように通常URLを書き換えるとフレーム(ウィンドウ)内のドキュメントは更新されてしまう(=状態が失わてしまう)けれども、URLの「#」以降のみを書き換える場合は、ドキュメントは更新されずにそのまま残る。

<iframe  id="ifr" src="http://www.example.com/" ></iframe>
<script type="text/javascript">
var ifr = document.getElementByid('ifr');
// 以下のスクリプトではフレーム内のドキュメントは更新されない
ifr.contentWindow.location.replace('http://www.example.com/#sayhello');
</script>

これを利用して、「#」以降の値のみを書き換えてやることにより、フレーム(ウィンドウ)の中にあるドキュメントに対して(クロスドメインであっても)外部から値を受け渡してやることが可能になる。受け取り側のドキュメントではスクリプトによってFragment Identifier(location.hash値)のポーリングを行う。長いメッセージの場合は分割してエンコードし、受け取り側のスクリプトでそれを結合しデコードする。

これによって2つのウィンドウ間だけでも一応クロスドメイン通信はできるけれども、実際に使う場合にクライアント側のドキュメントのFragment Identifier値が勝手に書き変わっては困るので、もうひとつ無害なフレームを用意することで、そのFragment Identifier値を書き換えるということを行う。この場合、クロスドメイン通信を行うドキュメントのスクリプトからアクセスできるように、新しいフレームはクライアントとなるドキュメントの置かれているドメインと同じドメインである必要がある。これがDojoではxip_client.htmlというHTMLファイルであり、GData(上記記事ではiframe内iframeと書かれている)の場合は同一ドメインに置かれた任意の画像ファイルになる。

ということで、どちらも実は多重IFrameを使って入るのだけれども、DojoとGDataではフレームの入れ子の構成が違っている。←認識違い。少なくとも今のDojo(1.0)はそうやってないっぽい。

Dojo 1.0 のIframeXhrProxyの場合>

外側 --> 内側
(client document) xip_server.html xip_client.html
client server client

<GData JavaScript APIの場合>

外側 --> 内側
(client document) (GData response html) (image file in client domain)
client server client

また、Dojoの場合はレスポンス受信のみでなくリクエスト送信もFragment Identifierで行っているが、GDataの場合は送信は通常のForm Postになる。DojoはそのままXHRを模倣して汎用性を高めているのに対し、GDataはリクエスト送信時のロスをなくすように最適化していると考えればいいだろうか。あと、よく調べてないんだけど、facebookのJavaScript APIも同じようなことをやってるはずなので、これがどうやっているかもちょっと気になるところではある。

(追記)
Dojo 1.0.2での動作にあわせて修正
http://download.dojotoolkit.org/release-1.0.2/dojo-release-1.0.2/dojox/io/proxy/