HTTP Access Controlによるクロスサイト HTTPリクエスト制御のメモ

CORS(Cross-Origin Resource Sharing)とも呼ばれるようですが、この技術についていろいろ調べることがあったのでメモ書き。(最近いろいろ堕落してるんでサンプルコードはjQuery使用前提で)

例えばあるサイト(example.com)のHTMLに以下のようなスクリプトを書いた場合エラーとなり期待した動作をしてくれません。

<script type="text/javascript">
jQuery(function($){
  $.ajax("http://other.com/test/other", {
  }).done(function(data, textStatus, jqXHR){
    alert(textStatus);
    $('#res').html(data);
  }).fail(function(jqXHR, textStatus, errorThrown){
    alert(textStatus);
  });
});
</script>

<div id="res">
</div>

これは、XMLHttpReuqestの送り先のホストが example.com上に存在しないから です。これが自由に出来てしまうといろいろと困った問題が起きるのでこんな ことになっているのですが、そうは言っても異るドメイン間でデータを共有したいというシーンは結構あったりするのもまた事実です。

そんな要求もあったのか、モダンなブラウザでは Access-Controll-Allow-Originヘッダをサーバ側で付けることにより、異なるドメイン間でもリクエストを受けとり処理ができるようにすることができます。

記の例についていえばXMLHttpRequestでリクエストを投げるコンテンツ (つまり http://other.com/test/other )のレスポンスヘッダに

Access-Control-Allow-Origin: *

を追加するとOKです。ちなみに「*」はどのホストからのリクエストでも 許可するという意味です。特定のホストからのリクエストのみ許可する 場合は

Access-Control-Allow-Origin: http://example.com

のように返します。

ちなみにこのような異なるドメインにリクエストを投げる場合、 XMLHttpRequestはクレデンシャル(つまり資格情報、もっとありていに言えば Cookieとか)の情報を送りません。

クレデンシャルをもリクエストで送りたい場合は example.com 内での XMLHttpRequestオブジェクトのプロパティ withCredentialstrue にしてさらに other.comのレスポンスヘッダに

Access-Control-Allow-Credentials: true

を追加してやる必要があります。この場合「*」のようにどこからでもOK というのは設定できないので、明示的にホスト名を書く必要があります。 参考までに上記のヘッダを jQueryで実現するには以下のようになります。

<script type="text/javascript">
jQuery(function($){
  $.ajax("<%= @other_url %>/test/other", {
    xhrFields: {
      withCredentials: true
    }
  }).done(function(data, textStatus, jqXHR){
    alert(textStatus);
    $('#res').html(data);
  }).fail(function(jqXHR, textStatus, errorThrown){
    alert(textStatus);
  });
});
</script>

<div id="res">
</div>

この機能がいつからあるのかは知りませんが少なくともW3Cを見る限りだと 2005年あたりから議論が始まりの2008年の9月のドラフトでこのヘッダ名になっ ているようです。Firefoxなどでは結構古くから実装されているみたいですね。 IE10でもサポートされているようなのでXPが死んだら広く使われるようになる??かもしれません。

参考リンク

サンプルおいときました

https://github.com/i10a/access_controll_test