メモログ

grunt-contrib-connect タスクで CORS を有効にする

grunt-contrib-jasmineの Third party templates にあるCode coverage output with Istanbulを使って jasmine テストの coverage の計測をしようとしているのですが、XMLHttpRequest を実行するところで Cross Origin の制約にひっかかってエラーになってしまう。localhost で実行されるのが理由かなとは思われるのですが、普通に jasmine テストを実行した場合はひっかからない不思議…(エラーに「file://」が出ているのも不明) jasmine の coverage 用のタスクのオプションで host を localhost に指定していなかったためだった。そのため、localfile system (file://) で起動していた… 設定を追加したら CORS の設定は必要なかった。

XMLHttpRequest cannot load http://localhost:9002/foobar.js. Origin file:// is not allowed by Access-Control-Allow-Origin.

理由はさておき、Access-Control-Allow-Origin(HTTP access control (CORS)参考)を設定すれば、エラーを抑制できるはず(javascript - Origin is not allowed by Access-Control-Allow-Origin - Stack Overflowも参考)。grunt-contrib-connectでサーバーを立ち上げて PhantomJS がそこから Jasmine specs を実行するようにしているので、grunt-contrib-connect に CORS の設定をする。

grunt-contrib-connect で立ち上げたサーバーの header に Access-Control-Allow-Origin を追加するには… middleware のオプションを使うと良いらしい。middleware のオプションは、return に function の配列を渡すことで、渡した function を順繰り実行してくれるみたい。Access-Control-Allow-Origin の追加方法は、Allowing CORS (Cross-Origin Resource Sharing) requests from grunt serverを参考にしました。この Gist のだけだと、grunt-contrib-connect のタスクでデフォルトで設定されている middlewareが実行されなくなってしまうので、デフォルトで設定されている function も一緒に追加する。すると、こんな感じの設定になる。

test: {
  options: {
    hostname: 'localhost',
    port: 9002,
    keepalive: true,
    middleware: function (connect, options) {
      return \[
        function (req, res, next) {
          res.setHeader('Access-Control-Allow-Origin', '*');
          res.setHeader('Access-Control-Allow-Methods', '*');
          next();
        },
        // Serve static files.
        connect.static(options.base),
        // Make empty directories browsable.
        connect.directory(options.base)
      \];
    }
  }
},

これで Cross Origin のエラーが発生することなく、coverage の計測が完了するようになりました。

というメモ

私について

Yutaka Yamaguchi
東京在住。TypeScript, Node.js, Reactなどフロンエンドが主力。Perlも書く。SwiftやRubyも過去には使ってた。過去のTOEIC 860くらい。