Node.jsからsocket.io-clientを使うときにクッキーを設定するには

  • 投稿日:
  • by

だいぶマニアックな情報ですが備忘メモとして書いておきます。

socket.io 1.0系の話です。0.9系は分かりません。

おそらく、普通のブラウザでsocket.io-clientを使う場合はクッキーは共通なので困らないと思いますが、node.jsからsocket.io-clientを使う場合はどうやるのでしょうか。

ところで、node.jsからsocket.io-clientを使いたい理由は、テストコードのためです。socket.io-clientはよくできていて、ブラウザでもnode.jsでも動くようです。

なぜ、クッキーを設定したいかというと、セッション維持のためです。サーバ側でなんらかの方法で認証して、セッションIDをクッキーに格納するというのはよくある方法だと思いますが、それをテストコードで動作確認したいわけです。

さて、本題です。socket.io-clientはengine.io-clientに依存していて、engine.io-clientはxmlhttpreuestやws (WebSocket)のライブラリに依存しています。socket.io-clientからそれらのライブラリにクッキーの情報を明示的に渡す手段は見つかりません。そもそも、テストコードを書くときくらいしか使わないのでしょう。

いろいろ調べた結果、engine.io-clientのv0.7.0からagentをオプションで渡せるようになっていました。socket.io-clientからengine.io-clientへはそっくりそのままオプションが引き継がれます。

agentというのは、httpのソケットを管理する仕組みなのですが、ちょっとそこを用途外利用することにしました。つまり、リクエストを登録しにきたところをフックして、クッキーのヘッダを追加してしまうのです。

コードはこんな感じです。

var http = require('http');
var socket_io_client = require('socket.io-client');
var cookie = 'aaa=123';
var myAgent = new http.Agent();
myAgent._addRequest = myAgent.addRequest;
myAgent.addRequest = function(req, host, port, localAddress) {
  var old = req._headers.cookie;
  req._headers.cookie = cookie + (old ? '; ' + old : '');
  req._headerNames['cookie'] = 'Cookie';
  return myAgent._addRequest(req, host, port, localAddress);
};
var client = socket_io_client('http://localhost:12345/', {
  agent: myAgent
});

クッキードメインのチェックは省略されています。テストコード以外では使えないでしょう。また、将来的に仕様が変わったら使えなくなる可能性もあります。