Server-Sent Events とは

JavaScript の EventSource インターフェースから使える、 HTTP 上で Push Notification を実現するためのもの。近々 CORS サポートも標準仕様になるらしい。サポート状況は PC だと IE だけ使えないというお決まりパターンで、モバイルだと iOS Safari のみ対応。 (参考:http://caniuse.com/eventsource)

コネクションは接続しっぱなしなので、都度リクエストを飛ばす Comet よりも効率的で MXHR 寄り。ライブラリ使わずに済むので全ブラウザで EventSource がサポートされれば相当嬉しい機能。接続のリトライ等はブラウザ側で扱ってくれたりするので地味に使い勝手が良さそう。

実装

適当なフレームワークといえば Tatsumaki だろうということで、 Server-Sent Events を追加して pull request 出しておいた

クライアント側で書くべきはこれだけなのでなかなか使いやすい。

var e = new EventSource("/chat/foo/sse");
e.addEventListener("message", function (payload) {
    var data = JSON.parse(payload.data)
    onNewEvent(data);
});

ブランチを checkout して http://0.0.0.0:5000/chat/foo?sse=1 とかでアクセスすれば Server-Sent Events を使ったチャットが使える。 Chrome だと response に何も出なくて何が起きているか全然わからないので、途中 console.log() を挟みつつ挙動を見てください。

サーバサイド

GET に対して Content-Type を text/event-stream でレスポンスして、その後は \n\n 区切りの行ベースでイベントを返してやれば良い。

GET /chat/foo/sse HTTP/1.1

HTTP/1.0 200 OK
Content-Type: text/event-stream

event: message
data: {"message": "Hi", "username": "foo"}

event: message
data: {"message": "Hi", "username": "bar"}

フィールドは event, data, id, retry が指定できる。 data フィールドは UTF-8 のテキストであれば良いので JSON 以外も使える。 コロン (:) から始まる行はコメントになる。

クライアントサイド

EventSource インスタンス生成して event を指定して event listener を追加してやると、ブラウザ側でイベント名に応じて event listener に送られる。 message event を処理するなら次のように書けばよい。

var e = new EventSource("/chat/foo/sse");
e.addEventListener("message", function (payload) {
    var data = JSON.parse(payload.data)
    onNewEvent(data);
});

参考リンク