Node.js での Heroku の WebSocket の使用
この記事の英語版に更新があります。ご覧の翻訳には含まれていない変更点があるかもしれません。
最終更新日 2024年05月15日(水)
Table of Contents
このチュートリアルでは、Heroku 上のリアルタイム Node.js アプリケーションの概要を説明します。サーバーの現在時刻を永続的なソケット接続経由でクライアントと共有する単純なアプリケーションを開発します。各アプリケーションは、Node の一般的な express
Web サーバーに基づきます。
リアルタイム Node.js アプリケーションを開発する場合は、直接 WebSocket を使用できます。WebSocket プロトコルをサポートしていないクライアントにフォールバックを提供する Socket.io などの抽象化ライブラリを使用することもできます。両方のオプションを示します。
dyno を使用してこのチュートリアルを完了した場合、使用量のカウントに入ります。低料金プランを使用してこのチュートリアルを完了することをお勧めします。資格のある学生の皆様は、新しい Heroku for GitHub Students プログラムを通じてプラットフォームクレジットを申請できます。
新しいアプリの作成
アプリのディレクトリに移動し、デフォルトの package.json
を作成します。
$ npm init --yes
package.json
で Node のバージョンを指定し、アプリを起動するためのメカニズムを指定します。
"engines": {
"node": "20.x"
},
"scripts": {
"start": "node server.js"
}
オプション 1: WebSocket
WebSocket 接続を使用するための最も簡単な方法は、Node の ws モジュールの直接の使用です。アプリを設定するための各手順について説明しますが、GitHub の完全なソースを参照することもできます。
依存関係のインストール
基本的な express
Web サーバーから始めましょう。
$ npm install --save express
WebSocket の場合は、ws
と bufferutil
および utf-8-validate モジュールをインストールします。必要なのは ws
モジュールだけですが、bufferutil
および utf-8-validate
モジュールによりパフォーマンスが向上します。
$ npm install --save ws bufferutil utf-8-validate
HTTP サーバーの作成
HTTP サーバーは、次の 2 つのことを行うために必要です。つまり、クライアント側のアセットを提供し、WebSocket サーバーにリクエストを監視するためのフックを提供します。サーバーコードは次のようになります。
const PORT = process.env.PORT || 3000;
const INDEX = '/index.html';
const server = express()
.use((req, res) => res.sendFile(INDEX, { root: __dirname }))
.listen(PORT, () => console.log(`Listening on ${PORT}`));
WebSocket サーバーの作成
WebSocket サーバーは、イベントをリッスンできるように、HTTP サーバーを引数として受け取ります。
const { Server } = require('ws');
const wss = new Server({ server });
接続の処理
接続と切断をリッスンしてログに記録します。クライアントが接続されたら、そのクライアントからのメッセージのためのイベントハンドラを追加できます。サーバーコードは次のようになります。
wss.on('connection', (ws) => {
console.log('Client connected');
ws.on('close', () => console.log('Client disconnected'));
});
更新のブロードキャスト
ソケット接続の利点の 1 つは、サーバーがクライアントリクエストを待機することなく、データをクライアントにブロードキャストできることです。この場合は、現在時刻をすべてのクライアントに 1 秒おきにプッシュします。
setInterval(() => {
wss.clients.forEach((client) => {
client.send(new Date().toTimeString());
});
}, 1000);
WebSocket クライアントの作成
クライアント index.html
は、サーバーからの時刻の更新をリッスンする単純な HTML ページです。クライアントコードは HTML で <script>
タグの間に記述でき、次のようになります。
var HOST = location.origin.replace(/^http/, 'ws')
var ws = new WebSocket(HOST);
var el;
ws.onmessage = function (event) {
el = document.getElementById('server-time');
el.innerHTML = 'Server time: ' + event.data;
};
アプリの起動
これでサーバーを起動できるようになりました。
$ npm start
> node server.js
Listening on 3000
http://localhost:3000 でアプリをローカルにテストして、時刻がリアルタイムに更新されることを確認します。サーバーログにも Client connected
と記録されます。
動作に満足したら、.gitignore
に追加する node_modules
を除いたすべてのファイルを Git にコミットします。次に、アプリを Heroku にデプロイします。
$ heroku create
$ git commit -am 'websocket starting point'
$ git push heroku main
$ heroku open
オプション 2: Socket.io
Socket.io などのリアルタイム抽象化ライブラリは、アプリが WebSocket のサポートなしでユーザーに対応するのに役立ちます。Socket.io はまた、ルーム、名前空間、自動再接続などの一般的な機能も提供します。アプリを設定するための各手順について説明しますが、GitHub の完全なソースを参照することもできます。
依存関係のインストール
このアプリには、基本的な express
Web サーバーと socket.io が必要です。
$ npm install --save express socket.io
HTTP サーバーの作成
HTTP サーバーは、次の 2 つのことを行うために必要です。つまり、クライアント側のアセットを提供し、Socket.io に socket.io 関連のリクエストを監視するためのフックを提供します。サーバーコードは次のようになります。
const PORT = process.env.PORT || 3000;
const INDEX = '/index.html';
const server = express()
.use((req, res) => res.sendFile(INDEX, { root: __dirname }))
.listen(PORT, () => console.log(`Listening on ${PORT}`));
Socket.io サーバーの作成
Socket.io サーバーは、socket.io 関連のリクエストをリッスンできるように、HTTP サーバーを引数として受け取ります。
const io = socketIO(server);
接続の処理
クライアントの接続と切断をログに記録します。クライアントが接続されたら、クライアントメッセージを受信するためのイベントハンドラを SocketIO インスタンスに追加できます。
io.on('connection', (socket) => {
console.log('Client connected');
socket.on('disconnect', () => console.log('Client disconnected'));
});
更新のブロードキャスト
永続的なソケット接続の利点の 1 つは、サーバーがクライアントのリクエストを待機することなく、データをクライアントにプッシュできることです。この例では、サーバー上の現在時刻を 1 秒に 1 回プッシュします。
setInterval(() => io.emit('time', new Date().toTimeString()), 1000);
Socket.io クライアントの作成
クライアント index.html
は、サーバーからの時刻の更新をリッスンする単純な HTML ページです。クライアントコードは HTML で <script>
タグの間に記述でき、次のようになります。
var socket = io();
var el;
socket.on('time', function(timeString) {
el = document.getElementById('server-time')
el.innerHTML = 'Server time: ' + timeString;
});
アプリの起動
これでサーバーを起動できるようになりました。
$ npm start
> node server.js
Listening on 3000
http://localhost:3000 でアプリをローカルにテストして、時刻がリアルタイムに更新されることを確認します。サーバーログにも Client connected
と記録されます。
動作に満足したら、node_modules
は .gitignore
に追加し、それ以外のすべてのファイルを Git にコミットします。次に、アプリを Heroku にデプロイします。
$ heroku create
$ git commit -am 'socket.io starting point'
$ git push heroku main
$ heroku open
Socket.io を使用するアプリでセッションアフィニティを有効にします。Node の Cluster モジュールを使用するか、またはアプリを複数の dyno にスケーリングする予定がある場合は、Socket.io の複数ノードの手順に従います。
$ heroku features:enable http-session-affinity