半年ほど悩んでいたのですがやっと解決できたのでまとめます。
WebsocketではHTTPをUpgradeしたプロトコルとして扱われ、COMETとは違いajaxやiframeなどによるコネクションをポーリングする技術とは異なる双方向通信を実現するプロトコルです。
なのでWebsocket自体に予約されたポートは無く、クライアントからは80や443で通信することも可能です。といっても、サーバー側がWebsocketに対応している必要があります。
前提条件
- Apache2.4以上
- mod_proxy_wstunnel がロードされている
- mod_rewrite がロードされている
同じURIだけど、websocketとhttp両方見れるようにしたい
例えばストリーミングを行うAPIがあったとします。
/api/v1/streaming
このAPIのリクエスト時に、 http://(https://)であれば、 COMET等の技術によりコネクションがポーリングされストリーミングで受信処理が行われる用にしたいが、
ws://(wss://) の場合は、websocketでストリーミングで受信処理を行わるようにしたい場合、Apacheでは下記のようにすると問題が出ます。
ProxyPass /api/v1/streaming/ ws://localhost:4000/ ProxyPassReverse /api/v1/streaming/ ws://localhost:4000/ ProxyPass /api/v1/streaming/ http://localhost:4000/ ProxyPassReverse /api/v1/streaming/ http://localhost:4000/
これだと、最初のProxyPassで潰されてしまい、httpの通信に失敗してしまいます。
この場合、wsの場合はmod_rewriteを使うことで解決できます。
websocketは、ConnectionがUpgradeになるので、それをrewriteの条件に指定することでwebsocketの場合のみwsに接続するように変更する事ができます。
RewriteEngine On RewriteCond %{HTTP:Connection} Upgrade [NC] RewriteCond %{HTTP:Upgrade} websocket [NC] RewriteRule /api/v1/streaming/(.*) ws://localhost:4000/api/v1/streaming/$1 [P,L] ProxyPreserveHost On ProxyPass /api/v1/streaming/ http://localhost:4000/api/v1/streaming/ ProxyPassReverse /api/v1/streaming/ http://localhost:4000/api/v1/streaming/ ProxyPass / http://localhost:3000/ ProxyPassReverse / http://localhost:3000/