WebSocketは、最初にHTTPを利用して接続を確立した後、同じ接続を維持したままクライアントとサーバーが双方向にデータを送受信できる通信方式です。通常のHTTP通信ではクライアントからのリクエストを起点にレスポンスが返りますが、WebSocketでは接続中であればサーバー側からも任意のタイミングでメッセージを送れます。チャット、リアルタイム通知、進捗表示のように即時性が必要な機能に向いていますが、切断、再接続、認証期限切れ、接続数の管理なども設計に含める必要があります。

1. WebSocketとは
1-1. 接続を維持して双方向に通信する仕組み
WebSocketは、クライアントとサーバーが接続を維持しながら、双方向にメッセージを送受信するための通信方式です。ブラウザとサーバーの間で、リアルタイム性の高いデータ交換を行いたい場面で使われます。
通常のHTTP通信では、クライアントがリクエストを送り、サーバーがレスポンスを返す流れが基本です。一方、WebSocketでは一度接続が確立されると、その接続上でクライアントからサーバーへ送るだけでなく、サーバーからクライアントへも任意のタイミングでメッセージを送れます。この「接続を開いたままにする」点が、一般的なHTTPリクエストとの大きな違いです。
たとえば、チャットで相手のメッセージをすぐ受け取りたい場合、毎秒HTTPで問い合わせるより、WebSocketで接続を維持してサーバーから通知してもらう方が自然です。ただし、WebSocketを使えば必ず実装が簡単になるわけではなく、接続が切れたときの再接続や、接続中の認証状態も考える必要があります。
1-2. 最初の接続ではHTTPハンドシェイクを利用する
WebSocketは、最初の接続確立時にHTTPハンドシェイクを利用します。ハンドシェイクとは、通信を始める前にクライアントとサーバーが接続条件を確認する手続きです。
ブラウザは最初にHTTPリクエストを送り、サーバーに対して「この接続をWebSocketへ切り替えたい」と伝えます。サーバーが対応していれば、HTTPの接続をWebSocket用の通信へアップグレードします。この仕組みにより、WebSocketはHTTPとまったく無関係に始まるのではなく、HTTPの仕組みを入口として使います。
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xxxxx
Sec-WebSocket-Version: 13
この例は、WebSocket接続を開始するときのHTTPハンドシェイクのイメージです。注意点は、開発者が通常のブラウザ実装でこれらのヘッダーを手動で組み立てることは少なく、ブラウザ標準のWebSocket APIが内部で処理してくれることです。仕組みとしてはHTTPから始まり、その後WebSocket通信へ切り替わると理解しておきましょう。
1-3. ws://とwss://の違い
WebSocketのURLには、ws://とwss://があります。安全な通信を行う本番環境では、基本的に暗号化されたwss://を使います。
ws://は暗号化されていないWebSocket通信で、HTTPに近い位置づけです。wss://はTLSで暗号化されたWebSocket通信で、HTTPSに近い位置づけです。ログイン済みユーザーの通知、チャット内容、認証情報に関係する通信では、通信内容の盗聴や改ざんを防ぐためにwss://を選ぶ必要があります。
const socket = new WebSocket('wss://example.com/ws/notifications');
このコードでは、暗号化されたWebSocket接続を開始しています。注意点は、ページがHTTPSで配信されているのにws://へ接続しようとすると、ブラウザのセキュリティ制約でブロックされる場合があることです。本番ではHTTPSと同じく、WebSocketもwss://を前提に設計しましょう。
2. HTTP通信との違い
2-1. HTTPは基本的にリクエストを起点に通信する
HTTP通信は、基本的にクライアントからのリクエストを起点にサーバーがレスポンスを返す仕組みです。GETやPOSTでAPIを呼び出す処理は、この形に当てはまります。
たとえば、ユーザー一覧を取得する場合、ブラウザがGET /api/usersを送り、サーバーがJSONを返します。フォーム送信では、ブラウザがPOSTでデータを送り、サーバーが登録結果を返します。このように、通常のHTTPでは「クライアントが聞いたことにサーバーが答える」流れが中心です。
通知件数やチャットの新着をHTTPだけで実現する場合、クライアントが定期的に「新しい情報はありますか」と問い合わせるポーリングが使われることがあります。更新頻度が低いなら十分ですが、高頻度で即時性が必要な場合は、問い合わせ回数や遅延が問題になることがあります。
2-2. WebSocketはサーバー側からも任意のタイミングで送信できる
WebSocketでは、接続が確立された後、サーバー側からも任意のタイミングでクライアントへメッセージを送信できます。これにより、リアルタイム通知やチャットのような機能を作りやすくなります。
WebSocketの接続中は、クライアントとサーバーのどちらもメッセージを送れます。クライアントが毎回リクエストを出さなくても、サーバーがイベント発生時に接続中のクライアントへ通知できます。ただし、これは「HTTPは一方向、WebSocketは双方向」という単純な話だけではありません。HTTPでもクライアントからサーバーへデータ送信はできますし、SSEのようにサーバーから継続的に送る仕組みもあります。
たとえば、チャットでAさんがメッセージを送ったら、サーバーは同じ部屋に接続しているBさんやCさんへすぐ配信できます。一方、1時間に数回しか変わらないデータを表示するだけなら、WebSocketではなく通常のHTTP取得で十分な場合もあります。
2-3. 接続、ヘッダー、通信頻度から比較する
HTTPとWebSocketは、接続の扱い、通信の起点、ヘッダー量、向いている利用場面が異なります。どちらが常に優れているのではなく、機能の性質に合わせて選びます。
HTTPはリクエストごとに意味が明確で、API取得、登録、更新、削除のような処理に向いています。WebSocketは接続を維持するため、頻繁な小さなメッセージをやり取りする場合に向いています。ただし、接続を維持する分、サーバー側では接続数、切断処理、再接続、スケーリングを考える必要があります。
| 比較項目 | HTTP | WebSocket |
|---|---|---|
| 通信の起点 | 主にクライアントのリクエスト | クライアントとサーバーの両方 |
| 接続 | リクエスト単位で扱いやすい | 接続を維持する |
| ヘッダー | リクエストごとにヘッダーが付く | 接続確立後はメッセージ中心 |
| 向いている処理 | 通常のAPI取得、登録、検索 | チャット、通知、ライブ更新 |
| 注意点 | 高頻度ポーリングでは無駄が増える場合がある | 接続管理や再接続設計が必要 |
この表は、HTTPとWebSocketの大まかな違いを整理したものです。注意点は、WebSocketなら必ず高速になる、負荷が下がる、と断定できないことです。通信頻度、接続数、サーバー構成、メッセージ量によって最適な選択は変わります。
3. WebSocket通信の基本的な流れ
3-1. ハンドシェイクで接続を確立する
WebSocket通信は、HTTPハンドシェイクで接続を確立してから始まります。ブラウザ標準のWebSocket APIを使うと、接続開始の処理を短く書けます。
JavaScriptでは、new WebSocket(url)で接続を開始します。接続が成功するとopenイベントが発生し、メッセージを送れる状態になります。サーバーがWebSocketに対応していない、URLが間違っている、認証に失敗する、ネットワークが遮断されるなどの場合は、接続できないことがあります。
const socket = new WebSocket('wss://example.com/ws/chat');
socket.addEventListener('open', () => {
console.log('WebSocket接続が確立しました');
socket.send(JSON.stringify({
type: 'join',
roomId: 'room-001'
}));
});
socket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log('メッセージを受信しました:', data);
});
socket.addEventListener('error', (event) => {
console.error('WebSocketエラーが発生しました:', event);
});
socket.addEventListener('close', (event) => {
console.log('WebSocket接続が閉じられました:', event.code, event.reason);
});
// 画面離脱や不要になったタイミングで切断する例
function disconnect() {
socket.close();
}
このコードでは、openで接続確立後の初期メッセージを送り、messageでサーバーからのデータを受信し、errorで通信エラーを検知し、closeで切断を扱っています。注意点は、これは最小イメージであり、本番では認証、再接続、JSON解析失敗、メッセージ形式の検証、画面破棄時の切断などを追加で考える必要があることです。
3-2. メッセージを送受信する
WebSocketでは、接続が開いている間、クライアントとサーバーがメッセージを送受信できます。ブラウザ側ではsendで送信し、messageイベントで受信します。
WebSocketで送るデータは、文字列やバイナリデータとして扱われます。実務では、メッセージの種類を表すtypeや、本文を表すpayloadを持つJSON文字列として送ることがよくあります。これにより、チャットメッセージ、参加通知、既読通知、進捗更新などを同じ接続上で区別できます。
socket.send(JSON.stringify({
type: 'chat_message',
payload: {
roomId: 'room-001',
text: 'こんにちは'
}
}));
このコードでは、チャットメッセージをJSON形式で送信しています。注意点は、WebSocketにはHTTPのようなURLやメソッドで処理を分ける考え方がそのままあるわけではないことです。メッセージごとのtypeやスキーマを決め、サーバー側で不正な形式を検証する必要があります。
3-3. 切断とエラーを処理する
WebSocketでは、切断とエラーが起きる前提で設計することが重要です。ネットワーク通信である以上、接続が常に維持されるとは限りません。
ユーザーが画面を閉じる、スマートフォンの通信が切れる、サーバーが再起動する、プロキシやロードバランサが接続を切るなど、WebSocket接続が閉じる理由はさまざまです。切断時にはcloseイベントが発生し、異常があればerrorイベントも関係します。アプリ側では、再接続するのか、ユーザーに通知するのか、未送信メッセージをどう扱うのかを決める必要があります。
たとえば、チャットでは一時的に切断されたあと自動再接続し、再接続後に未読メッセージをHTTP APIで取得する設計が考えられます。落とし穴は、切断を想定せず「接続はずっと続く」として実装することです。本番環境では、切断時の見た目、再接続回数、再接続間隔も運用上の重要なポイントになります。
4. WebSocketが向いている場面
4-1. チャットや共同編集などの双方向通信
WebSocketは、チャットや共同編集のように、クライアントとサーバーの双方が頻繁にデータを送る機能に向いています。双方向性が自然に必要になるためです。
チャットでは、ユーザーがメッセージを送るだけでなく、他のユーザーのメッセージを即時に受け取る必要があります。共同編集では、複数人の入力やカーソル位置、編集状態を短い間隔で共有することがあります。このような機能では、HTTPで何度も問い合わせるより、WebSocketで接続を維持してイベントを配信する設計が適する場合があります。
ただし、WebSocketだけでチャット機能が完成するわけではありません。メッセージの保存、既読管理、認可、履歴取得、スパム対策、切断中のメッセージ同期などは別途必要です。WebSocketはリアルタイムに届けるための通信手段であり、機能全体の設計は別に考えます。
4-2. ゲームや進捗表示などの高頻度更新
WebSocketは、高頻度で状態が変わる画面更新にも向いています。サーバー側の状態変化をすばやくクライアントに届けたい場合に使いやすいです。
たとえば、オンラインゲームの状態同期、ライブダッシュボード、ファイル処理の進捗表示、配送状況のリアルタイム更新などがあります。これらは、変化が起きたタイミングでサーバーからクライアントへ通知したい場面です。更新頻度が高い場合、HTTPポーリングでは無駄なリクエストが増えることがあります。
一方で、高頻度更新ではメッセージ量が増えやすく、クライアント描画やサーバー負荷も問題になります。すべての変化を逐一送るのではなく、送信間隔を調整する、差分だけ送る、古い更新をまとめるなどの設計が必要になる場合があります。
4-3. 通常のHTTPやSSEで十分な場面
WebSocketを使わなくても、通常のHTTP、ポーリング、SSEで十分な場面があります。WebSocketは万能な選択肢ではありません。
SSEはServer-Sent Eventsの略で、サーバーからクライアントへ一方向にイベントを送るための仕組みです。クライアントから頻繁に送信する必要がなく、サーバーから通知できればよい場合は、SSEが合うことがあります。また、更新頻度が低い通知や一覧再取得で十分な画面では、通常のHTTPや一定間隔のポーリングでも実装しやすいです。
たとえば、管理画面で数分に1回だけ状態が変わる一覧なら、HTTPで再取得するだけで十分かもしれません。サーバーからの一方向通知だけならSSEも候補です。双方向性や高頻度更新が本当に必要かを確認してから、WebSocketを選びましょう。
5. 導入前に知っておきたい注意点
5-1. 切断と再接続を前提に設計する
WebSocketでは、接続が切れることを前提に再接続設計を行う必要があります。接続を維持する仕組みだからこそ、切断時の扱いが重要になります。
ネットワーク不安定、端末のスリープ、ブラウザのタブ停止、サーバー再起動、ロードバランサのタイムアウトなどにより、接続はいつでも切れる可能性があります。再接続を行う場合も、短時間に大量の再接続が集中しないように、間隔を空ける、回数上限を設ける、ユーザー操作で再試行させるなどの工夫が必要です。
たとえば、全ユーザーが同時に再接続を繰り返すと、サーバーに大きな負荷がかかる場合があります。切断時には画面に「再接続中」と表示し、一定回数失敗したら通常のHTTP取得へ切り替えるなど、ユーザー体験と負荷の両方を考えましょう。
5-2. 認証と認可を接続後も確認する
WebSocketでも、認証と認可は重要です。接続時だけでなく、メッセージ処理時にも「誰が何をしてよいか」を確認する必要があります。
認証は「誰か」を確認することで、認可は「その人がその操作をしてよいか」を確認することです。WebSocketでは接続が長く続くため、接続開始時のトークンが途中で期限切れになる場合があります。また、接続済みだからといって、すべての部屋やデータへアクセスしてよいわけではありません。
たとえば、チャットルームにメッセージを送る場合、ユーザーがそのルームのメンバーかをサーバー側で確認する必要があります。クライアントから送られたroomIdを信用するだけでは不十分です。接続時の認証、メッセージごとの認可、期限切れ時の再認証を設計しましょう。
5-3. 接続数と複数サーバー構成を考慮する
WebSocketを本番運用するなら、接続数と複数サーバー構成を考慮する必要があります。HTTP APIと同じ感覚だけでは運用しづらい場面があります。
WebSocketは接続を維持するため、同時接続数がサーバー資源に影響します。ユーザー数が増えると、接続管理、メッセージ配信、サーバー間の状態共有が課題になります。複数サーバーで運用する場合、あるユーザーの接続がどのサーバーにあるのか、別サーバーからどう通知するのかも考える必要があります。
たとえば、サーバーAに接続しているユーザーへ、サーバーBで発生したイベントを届けたい場合、Redis Pub/Subやメッセージブローカーなどを使ってサーバー間でイベントを共有する設計が必要になることがあります。小さな機能では単純でも、利用者が増えると運用設計が重要になります。
6. WebSocketを選ぶための判断基準
6-1. 双方向性と更新頻度を確認する
WebSocketを選ぶ前に、本当に双方向性と高い更新頻度が必要かを確認しましょう。この2つが弱い場合、WebSocket以外の方法で十分なことがあります。
双方向性が必要とは、クライアントからサーバーへ送るだけでなく、サーバーからクライアントへもイベント発生時に送りたい状態です。更新頻度が高いとは、数秒単位またはそれより短い間隔で状態が変わり、ユーザーがすぐ知る必要がある状態です。どちらも当てはまる場合、WebSocketの候補になります。
たとえば、チャットや共同編集はWebSocketが向いている可能性が高いです。一方、1日に数回更新されるお知らせ一覧ならHTTPで十分です。「リアルタイムっぽく見せたい」だけでなく、実際にどの程度の即時性が必要かを要件として確認しましょう。
6-2. 実装・運用コストと比較する
WebSocketを選ぶときは、実装コストだけでなく運用コストも比較することが重要です。接続を維持する仕組みには、通常のHTTP APIとは違う管理が必要です。
WebSocketでは、接続開始、切断、再接続、認証期限切れ、メッセージ形式、接続数、サーバー間配信、監視、障害時の復旧を考えます。通常のHTTP APIなら、リクエストごとに認証し、レスポンスを返して終わる設計にしやすいです。WebSocketは便利ですが、アプリケーションとインフラの両方に考慮点が増えます。
たとえば、少人数向けの管理画面でたまに進捗が変わるだけなら、HTTPポーリングのほうが実装も運用も簡単な場合があります。逆に、多人数のチャットで即時配信が要件なら、WebSocketを検討する価値が高くなります。
6-3. WebSocketを使わない選択肢も検討する
WebSocketの導入判断では、使わない選択肢も比較対象に入れることが大切です。技術選定では、実現したい体験に対して最も扱いやすい方法を選びます。
候補には、通常のHTTP取得、一定間隔で問い合わせるポーリング、サーバーから一方向に通知するSSE、外部のリアルタイム配信サービスなどがあります。WebSocketは双方向通信に強い一方、接続管理の負担があります。SSEは一方向通知に向き、HTTPは単純な取得や更新に向いています。
たとえば、通知バッジの件数を30秒ごとに更新するだけならポーリングで十分かもしれません。サーバーから一方向に進捗を流すだけならSSEも候補です。チャットのように相互に頻繁なやり取りがある場合はWebSocketを検討しましょう。
7. まとめ
7-1. WebSocketとHTTPの違いを整理する
WebSocketは、接続を維持しながらクライアントとサーバーが双方向に通信する仕組みです。通常のHTTP通信とは、接続の扱いとサーバーから送信できるタイミングが大きく異なります。
HTTPは、GETやPOSTのようにクライアントのリクエストを起点に処理するAPIに向いています。WebSocketは、チャット、共同編集、通知、ライブ更新のように、接続中に何度もメッセージをやり取りする機能に向いています。ただし、WebSocketはHTTPの完全な代替ではなく、通常のAPI取得や登録処理ではHTTPのほうが自然な場面も多いです。
また、WebSocketではws://とwss://の違いを理解し、本番では安全なwss://を使うことが重要です。導入時は、切断、再接続、認証、認可、接続数、複数サーバー構成まで含めて設計しましょう。
7-2. 導入判断のチェックリスト
WebSocketを導入する前に、リアルタイム性だけでなく、運用上の負担も含めて確認すると判断しやすくなります。
- サーバーからクライアントへ任意のタイミングで通知する必要があるか
- クライアントとサーバーの双方向通信が頻繁に発生するか
- 通常のHTTP、ポーリング、SSEでは要件を満たせないか
- 接続切断時の表示や再接続方法を設計しているか
- 認証期限切れやメッセージごとの認可を考えているか
- 本番環境で
wss://を使う設計になっているか - 同時接続数が増えたときのサーバー負荷を見積もっているか
- 複数サーバー構成でメッセージ配信できる設計か
- メッセージ形式、エラー形式、再送方針を決めているか
WebSocketは、リアルタイム通信を実現するための強力な選択肢です。一方で、接続を維持する技術である以上、通常のHTTP APIとは違う設計と運用が必要です。使うべき場面と使わない場面を見極めることで、保守しやすいリアルタイム機能を作りやすくなります。
8. 参考リンク
- MDN Web Docs: WebSocket API
https://developer.mozilla.org/en-US/docs/Web/API/WebSocket - RFC 6455: The WebSocket Protocol
https://www.rfc-editor.org/rfc/rfc6455 - WHATWG: WebSockets Standard
https://websockets.spec.whatwg.org/