コンテンツへスキップ
HexaTransfer
ブログへ戻る
技術詳解

WebSocket vs HTTP for ファイル転送: A Comparison

WebSocket and HTTP protocols for ファイル転送. Performance benchmarks, use cases, and implementation trade-offs explained.

ファイル転送においては、ほぼ常にHTTPが勝つ。ステートレスで、すべての企業プロキシを通過し、HTTP/2の多重化とHTTP/3のQUICの恩恵を受け、CDN、署名付きURL、S3のようなオブジェクトストレージAPIとクリーンに統合される。WebSocket(RFC 6455)はリアルタイムの双方向メッセージング——チャット、共同編集、ライブダッシュボード——には優れているが、大きなファイルの移動ではほとんど優位性がなく、キャッシュなし、CDNサポート不十分、中間経路問題、複雑なサーバーサイドのメモリ管理という明確なデメリットがある。NISCのガイドラインが推奨する安全なデータ転送の観点からも、TLS 1.3との統合が成熟しているHTTPが基本的に優れたベースになる。

コアプロトコルの違い

HTTPはリクエスト・レスポンス型で、ステートレスで、キャッシュ可能だ。各リクエストはヘッダーを持ち、サーバーまたはCDNに届き、レスポンスを返す。HTTP/2は1つのTCP接続上で多くのリクエストを多重化し、HTTP/3(RFC 9114)はQUICの上で動作しより良い損失回復とゼロRTT再開を提供する。WebSocketはHTTP Upgradeリクエストとして始まり、TCP接続をフルデュプレックスのフレームベースプロトコルに切り替える。アップグレード後、両者はいつでもメッセージを送れる。この永続的な双方向チャンネルはインタラクティブなアプリには強力だが、フローが圧倒的に一方向であるバルクファイル転送にはアーキテクチャ上の歪みが生じる。

スループットとレイテンシのベンチマーク

東京クライアントと米国東部サーバー間のギガビットリンクでの典型的なベンチマーク:HTTP/1.1のPUT単体はTCPウィンドウスケーリングの制限から約40〜80Mbps、HTTP/2マルチパート(8並列ストリーム、8MBパーツ)で400〜800Mbps、HTTP/3のQUICはパケット損失環境で10〜30%向上、バイナリフレームのWebSocketは単一接続フロー制御の制約から200〜500Mbps。距離が異なってもこのパターンは繰り返される。WebSocketが速いわけではない——底部はTCPで変わらない——が、並列HTTPリクエストほど接続を効率よく使えない。

チャンク化と再開可能アップロード

HTTPには明確に定義されたチャンクアップロード標準がある。tus.ioプロトコルはUpload-OffsetヘッダーのHTTP PATCHを使う。S3 Multipart Uploadはパート番号とETagでUploadPartを使う。どちらもネットワーク中断から回復し、IndexedDBに永続化した状態を使ってクライアントの再起動後も最後に成功したチャンクから再開できる。WebSocketのチャンク化はアドホックだ:独自のフレーミング、シーケンス番号、確認応答を定義する必要がある。チームごとに同じ車輪を再発明し、微妙なバグを持つことが多い。SocketIO、Primus、カスタムプロトコルはそれぞれ同じ問題を再発明している。

CDNとエッジの互換性

Cloudflare、CloudFront、Fastly、AkamaiなどのCDNは、エッジのPoP(接続点)でHTTPレスポンスをキャッシュし、グローバルなダウンロード時間をしばしば半減させる。静的オブジェクトへのGETリクエストはURLや署名付きURLでキャッシュできる。WebSocketトラフィックは通常CDNを通過するがキャッシュされず、TLSプロキシを傍受している多くの企業プロキシはWebSocketのアップグレードを無効化または抑制する。企業ネットワークのTLSを傍受するプロキシはWebSocketを完全に壊すことがある。グローバルなユーザーを持つファイル転送サービスにとって、これだけでHTTPを選ぶ理由として十分だ:CloudflareのPoP 300以上がHTTPの近くのダウンロードを劇的に速くするが、WebSocketペイロードにはほとんど何も提供しない。

サーバーサイドのリソース使用

HTTPサーバーはリクエストが短命なため最小限のメモリで何千もの同時接続を処理できる。nginx、caddy、GoのHTTPはそれぞれ適度なRAMでノードあたり10,000以上の同時接続をサポートする。WebSocket接続はTCPソケット、読み取りバッファ、書き込みバッファ、多くの場合アプリケーション状態を保持する長命なものだ。大規模では、WebSocketのフリートはulimit、TCPキープアライブ、接続ごとのメモリを慎重にチューニングする必要がある。Kubernetesデプロイは、ローリングデプロイ中のWebSocketのスティッキーセッションとグレースフルシャットダウンで問題に直面する。

署名付きURLとストレージへのダイレクトアップロード

ファイル転送におけるHTTPのキラー機能は署名付きURLだ。アプリはS3、R2、またはGCSを直接指す署名付きURLを生成し、クライアントはオブジェクトストレージに直接アップロードする。アプリサーバーはバイトを一切触らない。プロキシ帯域幅なし、メモリプレッシャーなし、ファイルI/Oなし。WebSocketに相当するものはない。WebSocketでアップロードするにはアプリサーバーを通じてプロキシする必要があり、そこからストレージに書き込むことになり、帯域幅コストが倍になりレイテンシが増加する。10GBのWebSocket経由のアップロードはサーバー帯域幅を20GB使うが、S3への直接HTTPアップロードは小さなメタデータコールにのみサーバー帯域幅を使う。

WebSocketが実際に有用な場面

WebSocketはファイルに隣接するワークフローにうまく適合する。タブやデバイスをまたいだリアルタイムのアップロード進捗通知:WebSocketブロードキャストは即座に配信する。協調ファイル編集:yjs、AutomergeなどのCRDTライブラリはWebSocketを小さなデルタメッセージに使い、実際の大きなアセットはHTTPで転送する。WebRTCのピアツーピア転送のライブシグナリング:P2Pデータチャンネルが開く前のWebSocketが標準的なシグナリングトランスポートだ。転送受信者がファイルをダウンロードしたことの、WebSocketによるサーバープッシュ通知はポーリングなしに送信者に即座に通知できる。パターンはWebSocketがイベントに、HTTPがバイトに使われることだ。

HTTP/2とHTTP/3の優位性

HTTP/2(RFC 7540)とHTTP/3(RFC 9114)はWebSocketがかつて利用していたギャップの多くを埋めている。HTTP/2は1つのTCP接続上で複数のリクエストを多重化し、オリジンごとの6接続制限を排除する。Server Pushでサーバーがプロアクティブにリソースを送信でき、ラウンドトリップを削減する。HTTP/3はQUICの上で動作し、接続全体をブロックする代わりにストリームごとにパケット損失を処理する——これはモバイルネットワークの不安定さに重要だ。EventSource(Server-Sent Events)はHTTPの上でサーバーからクライアントへの一方向プッシュを提供し、サーバーだけがプッシュする必要がある場合のWebSocketよりシンプルな代替手段になる。

セキュリティとオリジン制御

HTTPのセキュリティストーリーは成熟している。CORS(クロスオリジンリソース共有)はどのオリジンがアップロードまたはダウンロードできるかを制御する。CSP(コンテンツセキュリティポリシー)はクライアントのフェッチ先を制限する。TLS 1.3でトランスポートを保護する。署名付きURLにはHMAC署名が含まれ改ざんを防ぎ、正確なオブジェクトキーと有効期限にスコープできる。WebSocketのオリジン制御は弱い。Originヘッダーは非ブラウザクライアントでなりすませる。多くのWebSocketサーバーはオリジンを検証せず、クロスサイトのWebSocketハイジャック攻撃につながる。同等の保護を実装するには、すべてのフレームでの慎重なトークン検証が必要だ。

HexaTransferのようなファイル転送サービスには、HTTPプラスチャンクマルチパートプラスS3への直接アップロードが正しいアーキテクチャであり、ライブ進捗や受信者通知イベントのためにオプションでWebSocketを上に重ねることができる。

https://hexatransfer.com — 無料、アカウント不要、最大10GB。

エンドツーエンド暗号化で大容量ファイルを安全に送信

エンドツーエンド暗号化で最大10GBのファイルを無料で転送。アカウント不要。ファイルはアップロード前にブラウザで暗号化されるため、他の誰にも読まれません。

ファイルを送信