クロスドメインajaxのxhr2(CORS)を使ってみた感想


これまでjavascriptのXMLHttpRequest(XHR)による非同期通信のクロスドメインリクエストはブラウザの制約(same domain policy)により遮断されていました。

このsame domain policyについては以下によくまとまっていました。
http://d.hatena.ne.jp/hasegawayosuke/20130330/p1

私は遥か昔JS初心者だった頃ドメインを越えられないと知った時に衝撃を受けました。まぁもしこの制約が無かったら、やりたい放題ですからね。例えば掲示板に悪意のあるscriptを仕込んだり、ユーザーのcookieだとかなんでもサーバーに送れちゃったりしちゃう訳ですから、セキュリティ上しょうがない。

しかし、この制約を越えるために、先人のフロントエンド系の技術者達は当初ブラウザが想定指定なった様々なハックを考えだしたのです。例えば、ざっと思いつく有名なものをあげてみます。

JSONP

クロスドメインによるロードが許可されているscriptタグを用いて通信を行い、サーバー側が返すレスポンスをJSのfunctionで包んだ形にするもの。通常request時にcallback名を指定して、responseがcallbackFunc({“success”: true});のような形で返すことにより、xhrでハンドルできたようなsuccess callbackを実現できる。ただし、注意点はscriptタグによるものなので、headerの追加やPOSTによるリクエストなどはできない。単なるscriptタグなので当然ブラウザのサポート範囲が広く、jQuery等使えばお手軽にできるので、GETでクロスドメインでかつサーバー側に手を入れられるならオススメ。

proxy

同じドメイン上にservletなりPHPなどのproxyを置いて、サーバー側から指定のクロスドメインの通信を行う方法です。これが可能であればクライアント側は特に何もする必要はないので楽ですね。

imageタグ

投げっぱなしの通信ならimgタグのsrcに記述すれば可能(ビーコンと呼ばれている)。レスポンスを気にせず、例えばどこかに仕込んだイイネボタンのようなものから自社ドメインに結果を送るだけなどの用途にはよさそう。

postMessage

割と最近(?)できた仕組みです。iframeとの間でmessageのやり取りができる仕組みです。これにより双方のページにやり取りするためのscriptを配置できるのであれば安全に通信することができます。以下に具体例を交えている記事がありました。ただ、ブラウザのサポートの問題等もあり、身の回りではあまり流行っていない印象(?) 。
http://www.knockknock.jp/archives/221

他にもiframeを使用してPOST通信する方法等色々あると思いますが、だいたいどれも少しhack的であんまり王道的なものはありませんでした。

そんなこんなでWebクライアント系の開発者は長年クロスドメイン通信ができない制約に悩まされていた訳ですが、近年サーバー側が事前にresponse headerを積んで許可しておけばクロスドメインによるxhrが(正式に)可能になってきています。

XHR2と呼ばれる手法です。CORS(Cross-Origin Resource Sharing)とも呼ばれています。

つまりxhr2の登場でようやくフロントエンドの技術者達派胸を張って堂々とクロスドメイン通信ができるようになってきているのです!

通信の仕方は実はクライアント(JS)側のコードに変更を加える必要は基本的には無し!(基本的にはと書いたのは、場合によってはサーバーとの規約でcustom headerなどが必要になってくるからです。)

サーバー側はAccess-Control-Allow-Originというヘッダーをレスポンスに付与して、許可するドメインを追加します。他にもいくつか許可するmethodなどを返してあげます。

そうするだけで、あとはブラウザ任せでxhr通信ができます。つまりサーバー側が特定のドメインを事前に許可すればいくらでも非同期通信を行えるようになった訳です。

ただ、一点サーバー側がしっておかなければならないことは、シンプルなGETとPOSTのリクエストならそれだけで良いのですが、少し複雑な通信になった場合、ブラウザはpreflight requestというOPTIONSメソッドによる確認のための通信を本来の通信の前に勝手に送ります。

例えば、普通につくrequest header以外のもの(custom header等)がついている場合や、POSTの時のcontent-typeがapplication/x-www-form-urlencoded以外が指定されている場合などです。その場合はサーバー側で適切にOPTIONSのリクエストに対して200かつcross domain許可用のheaderを付けて返してあげましょう。

preflight requestが飛ぶ条件は以下のサイトによくまとまっていました!
http://dev.classmethod.jp/etc/about-cors/

あと、サポートブラウザには注意。
http://caniuse.com/cors

そんなこんなで最近xhr2に始めて触れて、色々試行錯誤していたので記事を書いてみました。
これから使う人はサーバー側の対応が場合によっては割と大変かもしれません。クライアント側はサーバーとの規約(post時のcontent-type等)について十分注意して使いましょう!