Webアプリケーションでは、従来のHTTPリクエストだけでなく、サーバーとクライアントが継続的にデータをやり取りする仕組みが必要になることがあります。
例えば、チャット、リアルタイム通知、ライブダッシュボード、共同編集ツールなどです。
このような用途で広く利用される技術の一つが WebSocket です。
本記事では、WebSocketの基本的な仕組みからNode.jsでの実装例、接続管理、セキュリティ対策までを紹介します。
1. WebSocketとは?
WebSocketは、クライアントとサーバーの間に双方向通信のための接続を確立するプロトコルです。
通常のHTTP通信では、クライアントがリクエストを送信し、サーバーがレスポンスを返します。
HTTP
Client → Request → Server
Client ← Response ← Server
一方、WebSocketでは接続が確立した後、クライアントとサーバーの双方からデータを送信できます。
WebSocket
Client ⇄ Server
双方向の継続的な通信
これにより、サーバー側で新しい情報が発生した際に、クライアントへデータを送信しやすくなります。
2. WebSocketが適している用途
WebSocketは、次のような機能に適しています。
- チャットメッセージ
- リアルタイム通知
- ライブダッシュボード
- 複数ユーザーによる共同編集
- 接続状態のモニタリング
一方、通常のフォーム送信や静的コンテンツの取得であれば、HTTPだけで十分な場合もあります。
技術を選ぶ際には、リアルタイム性が本当に必要かどうかを確認することが重要です。
3. Node.jsでWebSocketサーバーを作成する
今回は、Node.js向けのWebSocketライブラリであるwsを使用します。
まず、プロジェクトを作成します。
mkdir websocket-demo
cd websocket-demo
npm init -y
npm install ws
続いて、server.jsを作成します。
const WebSocket = require("ws");
const server = new WebSocket.Server({
port: 8080
});
server.on("connection", (socket) => {
console.log("Client connected");
socket.send(
JSON.stringify({
type: "welcome",
message: "Connected to WebSocket server"
})
);
socket.on("message", (data) => {
let message;
try {
message = JSON.parse(data.toString());
} catch {
socket.send(
JSON.stringify({
type: "error",
message: "Invalid JSON"
})
);
return;
}
if (
!message ||
typeof message.text !== "string" ||
message.text.length > 1000
) {
socket.send(
JSON.stringify({
type: "error",
message: "Invalid message format"
})
);
return;
}
socket.send(
JSON.stringify({
type: "ack",
message: "Message received"
})
);
});
socket.on("close", () => {
console.log("Client disconnected");
});
socket.on("error", (error) => {
console.error("WebSocket error:", error.message);
});
});
console.log("WebSocket server running on port 8080");
このサンプルでは、接続時のメッセージ送信、受信データの検証、エラー処理、切断イベントの監視を実装しています。
本番環境では、認証や接続数制限なども追加する必要があります。
4. ブラウザから接続する
ブラウザには標準のWebSocket APIが用意されています。
次のコードでサーバーへ接続できます。
const socket = new WebSocket(
"ws://localhost:8080"
);
socket.addEventListener("open", () => {
console.log("Connected");
socket.send(
JSON.stringify({
text: "Hello WebSocket"
})
);
});
socket.addEventListener("message", (event) => {
console.log("Received:", event.data);
});
socket.addEventListener("close", () => {
console.log("Connection closed");
});
socket.addEventListener("error", () => {
console.error("WebSocket connection error");
});
ローカル環境ではws://を利用できますが、本番環境では通常、HTTPSサイトに対応するwss://を使用します。
これにより、通信をTLSで保護できます。
5. メッセージ形式を統一する
リアルタイム通信では、メッセージの種類が増えるにつれて処理が複雑になります。
そこで、メッセージをJSON形式で統一し、typeなどのフィールドで種類を識別すると管理しやすくなります。
例えば、次のような形式です。
{
"type": "notification",
"payload": {
"title": "New update",
"createdAt": "2026-10-28T10:00:00Z"
}
}
アプリケーションでは、メッセージの種類に応じて処理を分けられます。
function handleMessage(message) {
switch (message.type) {
case "notification":
showNotification(message.payload);
break;
case "status":
updateStatus(message.payload);
break;
default:
console.warn("Unknown message type");
}
}
ただし、受信したJSONをそのまま信頼してはいけません。実際のアプリケーションでは、クライアントとサーバーの両方でメッセージ構造を検証します。
6. 接続状態を管理する
WebSocket接続は、ネットワークの切断やサーバーの再起動によって終了する場合があります。
ブラウザではreadyStateを利用して接続状態を確認できます。
if (socket.readyState === WebSocket.OPEN) {
socket.send(
JSON.stringify({
text: "Current status"
})
);
}
主な状態は次のとおりです。
| 状態 | 意味 |
|---|---|
| CONNECTING | 接続中 |
| OPEN | 接続済み |
| CLOSING | 切断処理中 |
| CLOSED | 切断済み |
送信前に状態を確認することで、閉じた接続への送信によるエラーを減らせます。
7. 再接続処理を設計する
モバイル環境では、ネットワークが一時的に切断されることがあります。
そのため、必要に応じて再接続処理を実装します。
ただし、切断直後に何度も接続を試みると、サーバーへの負荷が増加する可能性があります。
指数バックオフを利用すると、再試行の間隔を段階的に延ばせます。
let retryCount = 0;
let retryTimer;
function reconnect() {
const delay = Math.min(
1000 * 2 ** retryCount,
30000
);
retryCount += 1;
clearTimeout(retryTimer);
retryTimer = setTimeout(() => {
connect();
}, delay);
}
function connect() {
const socket = new WebSocket(
"wss://example.com/ws"
);
socket.addEventListener("open", () => {
retryCount = 0;
});
socket.addEventListener("close", () => {
reconnect();
});
}
このコードは基本的な考え方を示す例です。実運用では、再接続の上限、認証情報の更新、ページ終了時のタイマー解除、サーバー側の切断理由なども考慮します。
8. WebSocketのセキュリティ対策
WebSocketを導入する際には、通常のHTTP APIと同様にセキュリティ対策が必要です。
WSSを利用する
本番環境では、TLSで保護されたwss://を利用します。
接続時に認証する
接続を確立する際に、ユーザーの認証状態を確認します。
Originを検証する
ブラウザからの接続では、許可したOriginのみを受け入れるようにします。Origin検証だけで認証を代替することはできません。
メッセージを検証する
メッセージの形式、サイズ、許可された操作をサーバー側で確認します。
接続数と送信頻度を制限する
ユーザー単位の接続数やメッセージ送信頻度を管理し、過剰な負荷を防ぎます。
機密情報をログに記録しない
アクセストークンや個人情報などを、必要以上にログへ保存しないようにします。
これらを組み合わせることで、リアルタイム通信の安全性を高められます。
9. 多数の接続を管理する際の注意点
WebSocketは接続を維持するため、同時接続数が増えるとメモリやネットワークの使用量も増加します。
本番環境では、次の項目を監視するとよいでしょう。
- 同時接続数
- メッセージ送受信量
- 接続切断率
- メッセージ処理時間
- メモリ使用量
- 再接続の発生頻度
複数のサーバーを使用する場合は、接続先の管理やメッセージ配信の仕組みも設計する必要があります。
Redis Pub/Subなどの仕組みはサーバー間のイベント配信に利用できますが、メッセージの永続化や再配信が必要なシステムでは、別のメッセージング方式を検討することも重要です。
10. デジタルプラットフォームへの応用
リアルタイム通知やコンテンツ更新を扱うデジタルサービスでは、WebSocketを利用することで、ユーザーがページを再読み込みすることなく情報を受け取れる設計が可能になります。
例えば、JILIPH のようなデジタルプラットフォームを技術的な設計例として考える場合、通知機能、状態更新、リアルタイムダッシュボードなどにWebSocketを応用できます。
ただし、すべての情報をリアルタイムで配信する必要はありません。更新頻度が低い情報であれば、通常のHTTPリクエストやServer-Sent Events(SSE)の方が適している場合もあります。
必要なリアルタイム性、接続数、運用コストを比較して通信方式を選ぶことが重要です。
まとめ
WebSocketは、クライアントとサーバー間の双方向通信を実現する便利な技術です。
実装時には、次のポイントを意識しましょう。
- WebSocketの基本的な接続フローを理解する
- メッセージ形式を統一する
- 接続状態と再接続を管理する
- 本番環境ではWSSを利用する
- 認証、Origin検証、レート制限を実装する
- 同時接続数とメッセージ処理を監視する
- 要件に応じてHTTPやSSEとも比較する
リアルタイム機能はユーザー体験を改善できる一方で、接続管理やセキュリティへの配慮も必要です。小さなサンプルから実装を始め、実際の利用条件に合わせて段階的に拡張していくことが、安定したWebサービス開発につながります。