del.icio.us direc.torの謎

いや、謎ってほどのものじゃないんですが、噂のdel.icio.us direc.torを使ってみて、「あれ、Javascriptから直接del.icio.us apiを叩いてるみたいだけど、どうやってるんだろう?」と疑問に思ったので、調べてみました。

まず、del.icio.us direc.torは以下の様な順にHTTPリクエストを出しています。

  1. ブックマークレットからhttp://johnvey.com/features/deliciousdirector/dboot.js を呼び出して実行
  2. dboot.jsからhttp://johnvey.com/features/deliciousdirector/d.js を呼び出して実行
  3. d.jsからhttp://del.icio.us/api/posts/all を叩いて、del.icio.usの全ポストを取得

最初の2つは、最速インターフェース研究会のma.laさんが、[Ajax] JSAN構想とリモートデータの取得とUserJavaScriptでおっしゃっている通り、scriptタグを使って呼び出しているので、ドメインはどこでもいいわけですが、最後のdel.icio.us apiを叩いている部分はxmlHttpRequestを使っています。

自分の理解では、xmlHttpRequestでリモートデータを取得する場合、呼び出し元のJavascriptファイルが置いてあるドメインと、呼び出し先のウェブサーバのドメインが同じじゃないといけないと思っていたのですが、この動作を見てると、そうはなっていないようです。で、d.jsのソースを見てみると、xmlHttpRequestで /api/posts/all を叩いている部分は見受けられるものの、特にdel.ico.usという指定はされていません。

どうやら、一度del.icio.usを開いてからブックマークレットを実行してるところがポイントらしい、と思い、「同じじゃないといけないのは、呼び出し元のJavascriptファイルが置いてあるドメインではなく、Javascriptを呼び出しているページのドメインではないか?」という仮説を立てて、実験してみました。

まず、以下の様なJavascriptファイルを用意します。

function load() {
  try {
    xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
    try {
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {
      xmlhttp = false;
    }
  }
  if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
    xmlhttp = new XMLHttpRequest();
  }
  if (xmlhttp) {
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
      document.body.innerHTML = xmlhttp.responseText;
      }
    }
    xmlhttp.open('GET', '/');
    xmlhttp.send(null);
  }
}

load();

次に、こいつを呼び出すブックマークレットを作成します。こんな感じで。そしてブックマークに入れます。

どこか適当なウェブサイトを開きます。この時、http://www.google.co.jp/ といったドメインのトップのページではなく、http://www.google.co.jp/imode といった感じで、ディレクトリ名やファイル名が含まれるURLにアクセスして下さい。(javascriptでトップページを読み込んで表示させる、という実験なので、最初からトップページを開いていると、ページ遷移したことが分かりません。)

で、先のブックマークレットを実行します。すると、実行前に開いていたページが所属するドメインのトップページが表示されると思います。

というわけで、xmlHttpRequestのクロスドメインの問題は、「呼び出し元のJavascriptファイルが置いてあるドメインと、呼び出し先のウェブサーバのドメインが同じじゃないといけない」わけではなく、「Javascriptを呼び出しているページのドメインと、呼び出し先のウェブサーバのドメインが同じじゃないといけない」わけで、Javascriptファイルがどこにあっても関係ないようです。(もしかして常識?)

おそらく、ブックマークレットを使わなくても、呼び出し元のページを編集して、直接scriptタグによりJavascriptを呼び出すようにしてもいいんでしょうけど、編集できる権限があるぐらいなら、そもそもクロスドメインがどうとか考える必要はないわけで、ブックマークレットで呼び出すのが現実的なんでしょうね。