Socket.ioのクライアントスクリプトを本番環境向けに設定する方法

JavaScript

通常、Socket.ioのクライアントスクリプトは、起動しているサーバー側のURLから「/socket.io/socket.io.js」の様に取得するのだが、どうもこれがMinifyされていない。HTTPヘッダーに「Cache-Control」もついてないし、gzip圧縮転送もされていない。

本番運用向けのクライアントスクリプトに対する設定をしましょう。

スポンサーリンク

Socket.ioのソースコードを眺める

lib/manager.jsを見る限りだと、

, 'browser client': true
, 'browser client cache': true
, 'browser client minification': false

となっている。「browser client minification」をtrueにしてあげれば良いのだろう。

Manager.prototype.enable = function (key) {
  this.settings[key] = true;
  this.emit('set:' + key, this.settings[key], key);
  return this;
};

みたいなことになっているので、このあたりを利用して設定してあげる。

Minifyする

こんな感じにコードを書けば、クライアントスクリプトはMinifyされる。

var io = require('socket.io').listen(80);
io.enable('browser client minification');

ブラウザキャッシュ

Socket.ioのクライアントスクリプトなんて、Socket.ioのバージョンアップしない限りは、コードの中身が変わらないはずなので、HTTPヘッダーに「Cache-Control」などを追加して、ブラウザ側でキャッシュして欲しい。と考えていたところ、こんなつぶやきを発見した。

おぉ!じゃあ、さっそく。このとおり取得すると、残念ながら通常の取得と全く変わってない。

このあたりの作者のやりとりを見てると実装はやっぱりされている。

lib/manager.jsの上部あたりを見ると

    , 'browser client cache': true
    , 'browser client minification': false
    , 'browser client etag': false
    , 'browser client expires': 315360000

と設定されているので、Cache-Controlヘッダー付きで配信されてもおかしくないんだけどなぁ。

lib/static.jsがクライアントスクリプトを配信しているコードがかかれているのだろうけど、ここをのぞく限り

    // see if we need to set Expire headers because the path is versioned
    if (versioned) {
      var expires = self.manager.get('browser client expires');
      headers['Cache-Control'] = 'private, x-gzip-ok="", max-age=' + expires;
      headers['Date'] = new Date().toUTCString();
      headers['Expires'] = new Date(Date.now() + (expires * 1000)).toUTCString();
    }

と、実際の実装がきちんと書かれている。

  this.add('/socket.io.v', { mime: mime.js }, function (path, callback) {
    build(self.manager.get('transports'), callback);
  });

このあたりで、取得URLに対する処理が書かれているのだろうけど…。と途方に暮れていたところ、

test/static.test.jsで、クライアントスクリプト取得に関するテストが書いてある。コレをのぞいていくと…。

    cl.get('/socket.io/socket.io.v0.8.9.js', function (res, data) {
      res.headers['content-type'].should.eql('application/javascript');
      res.headers['content-length'].should.match(/([0-9]+)/);
      res.headers['cache-control']
        .indexOf(io.get('browser client expires')).should.be.above(-1);

という、テストを発見!!どうも内容をみると取得方法(バージョンの指定方法)が違うのである。

(*1)

と取得するのは誤りで、正しくは

「/socket.io/socket.io.v0.8.9.js」のように指定するべきである。

動作確認をしたところ、無事にHTTPヘッダーに「Cache-Control」が追加されていた。

Content-Type: application/javascript
Cache-Control: private, x-gzip-ok="", max-age=315360000
Date: Sun, 01 Jan 2012 21:39:35 GMT
Expires: Wed, 29 Dec 2021 21:39:35 GMT
Content-Length: 27339
Connection: keep-alive

gzipも有効にする

ついでだから、gzip圧縮しての転送を有効にしておこう

var io = require('socket.io').listen(80);
io.enable('browser client minification');
io.enable('browser client gzip');

最後に動作確認

/socket.io/socket.io.v0.8.7.js

--> HTTP/1.1 200 OK
    Content-Type: application/javascript
    Content-Length: 8228
    Content-Encoding: gzip
    Vary: Accept-Encoding
    Connection: keep-alive  

Content-Lengthが小さくなってますね。

以上、こんな感じで本番向けのクライアントスクリプトの設定ができました。実際に動作確認することはとても大事です。

ですが、テストコードが実装テストだけに役立つのではないということも知っていただきたいところです。

今回のように期待する動作と結果を追っていくだけでも、テストコードがあると的確に理解することができました。

不確実性のあるコードの意図や雰囲気だけでなく、具体的に動作する情報がテストコードです。

Christian Johansen

*1: 単なるtypoなんでしょうが、日本語情報が少ないので…

タイトルとURLをコピーしました