無気力生活 (ノ ´ω`)ノ ~゜

脱力系エンジニア。てきとーに生きてます。

mithril.jsとCORSの話

個人用のツールとして、最近話題になり始めてるmithril.js使ってるんですが、いいですよこれ。 react.jsと同じようにVirtualDomサポートしつつ、その上でAPIが16しかない(ここ重要)という素晴らしいJavascriptMVCフレームワークです。

github.com

react.js少し使っていて、JS側にテンプレート書けるJSXはそこそこ気に入っていたんですが、 素のブラウザで普通には動かせないんで大分辛みを感じてました。 このmithrilなら、素のブラウザで動作しつつ、react.jsのいいところも使えて大変便利です。 ちなみに、JSXのようなものを提供する拡張もあるようです。MSXだったかな?

さて、このmithril、こんな感じでAjaxRequestを発行することができます。

var users = m.request({method: "GET", url: "/user"})
    .then(log)
    .then(function(users) {
        //add one more user to the response
        return users.concat({name: "Jane"})
    })

まあ、これまんま公式から引っ張ってきたやつですが、いわゆるスタンダードなJqueryと比較して、callbackがchainで書けたりできるのでめちゃ使いやすいです。 素晴らしい。

そんなm.requestを使って起こった問題について書いてみます。 ここからが本題。

Access-Control-Allow-Origin

今回ターゲットにしているサービスは、完全に自分と関係ないやつなので、まあ、こいつと遭遇することになるわけです。
"No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access."

最近のブラウザでは標準搭載されているCross-Domainの制限ですね。
今回は自分の作ったJSと、サービスの公開ドメインが異なっているので、このアクセス制限を食らってしまうわけですねー。

詳しい話はこのへん https://developer.mozilla.org/ja/docs/HTTP_access_control http://qiita.com/zaru/items/6e57ab83a8e0e40f2115



当然、mithril限定の問題ではなく、他のライブラリ使っても発生する問題なので、対応方法も豊富に公開されていました。ありがたい限りです( ・`ω・´)

必要な対応としては3つ

  1. Jsonp使う
  2. サーバー側でAccess-Control-Allow-Originを返してあげるようにする
  3. プロキシ経由させて、プロキシ側でサービスにリクエスト送りつつ、Access-Control-Allow-Originをクライアントに返す

今回の接続先は、自分が管理していないサービスなので、1、2では対応できません。当然ですね(´・ω・`) となると必然的に3の選択を取ることになります。

なぜ3が有効かというと、Cross-Origin Resource Sharingは、あくまでクライアントから通信するときの制限であるため、 3で強制的にAccess-Control-Allow-Originをレスポンスとして返して上げることで、この問題を防ぐことができます。


ちなみにjqueryであれば、jquery.xdomainajax.js というものを使えば簡単に解決可能です。やってることも同じかんじ。 とはいえ、Yahooapiを経由してリクエストぶん投げる方法で、Yahooさんの意向一つで使えなくなる怖さはあるので、今回は自力で対応しています。

今回は、ツール開発で使ってるcoffeeScriptをugilifyしてsourcemapをはき出すためにgulpを使っており、node.jsとは切っても切れない関係になっているので、node.jsでプロキシ作成することにしました。

node.jsでの実装はこんな感じ

リクエスト発行するHTMLと、サーバーのドメインが異なると、それだけで弾かれてしまうので、HTMLやjsもnodeで配信するようにしました。
これで、クライアントとサーバーが同一ドメインであることが満たされるので、問題なく動作するようになります。