概要
本記事では、WebSocketのブラウザAPIでサーバ側からセッションを切断された場合、自動で再接続する方法について記します。
アプリ側としては、該当ページ表示期間中において常にセッションを張っておきたいにも関わらず、サーバ側としても意図せず切断(=Closeフレームの送信)するケースが存在するようです(ex. WebSocketのサーバ側でALBをかませる)。少なくともAWSのALBは最長4000秒の設定しか出来ず、それ以上セッションを張り続けたい場合は、ブラウザAPI側で手当てされていないため、切断されたら自動的に再接続する必要があります。
なお、今回は表題の通り、ソケット通信で有名なライブラリであるsocket.ioではなくブラウザAPIのWebSocket APIについて取り扱っていますのでご注意ください。
環境
$ node -v
v16.13.2
$ npm -v
8.1.2
動作確認したChromeのバージョン
Version 104.0.5112.101 (Official Build) (arm64)
実装
やっていることは非常にシンプルで、サーバから切断処理があった場合、クライアント側でcloseのイベントが発火されます。
このタイミングに合わせて、再度インスタンスを作り直すだけです。本実装により接続されたら自動で再接続し、イベントリスナーも貼り直すことができます。
import React, { useEffect, useState } from 'react';
const socketServerUrl = 'hogehoge';
export const WebSocketComponent = () => {
const [socket, setSocket] = useState<WebSocket>();
// ↓✨✨接続先サーバのURLを指定
setSocket(new WebSocket(socketServerUrl));
useEffect(() => {
socket != null &&
socket.addEventListener('close', function () {
// ✨✨【今回のポイント】closeイベント発火後、再度インスタンスを生成することで再接続する✨✨
setSocket(new WebSocket(socketServerUrl));
});
socket != null &&
socket.addEventListener('open', function () {
// 初期化処理実行
// socket.send('huhgahuga');
});
socket != null &&
socket.addEventListener('message', function (e) {
try {
// TODO: あなたのやりたい処理
} catch (e) {
console.log('error出たよ、', e);
}
});
}, [socket]);
// あなたが見せたいjsxを↓に書こう!
return <div>WebSocketComponent</div>;
};
おまけ
この辺、自分で実装するのではなくAPI側でオプションで用意してほしいのですが、自前で実装する必要性がありました。もし切断されて困るのであれば、本記事が皆様のお役に立てると嬉しく思います。
なお、実際の運用の現場で発生したのが、リトライした接続がセッション張ることに失敗したら、当たり前ですが切断されっぱなしになります。こうなると今回の対応では不十分です。
気が向いたら、接続状況を確認してリトライに失敗してもさらにリトライする処理を入れる処理を含めた記事を書こうと思います。