Xserver 共用レンタルで WordPress にチャットを入れたら、WebSocket も SSE もだめで Long Polling に落ち着いた話

XserverでWebSocketもSSEも動かない|共用レンタルでチャットを実現したLong Polling実装 Web Development
この記事は約9分で読めます。

Xserver の共用レンタルで動く WordPress に、チャット機能を入れようとしたことはありますか。もし入れるなら、最初に WebSocket だけへ全部を賭けないほうがいい、というのが私の結論です。2025年秋、私は3方式を順に試して、WebSocket は接続できず、SSE は配信が安定せず、最後に Long Polling で素直に動きました。以下、なぜそうなったかを、起きた順に書きます。コードは考え方を確認する最小サンプルで、コピペでの本番運用を意図したものではありません。VPS や自前で Node.js を立てられる環境なら、答えは変わります。

検証環境:WordPress 6.8.3 / Xserver 共用レンタル / PHP 8.3.21。検証は2025年秋、記事更新は2026年5月5日。

WebSocket、SSE、Long Polling の3方式の通信フロー比較

WebSocket は、なぜ共用レンタルで止まったのか

チャットと聞いて最初に思い浮かんだのが WebSocket でした。接続を開きっぱなしにして双方向にやり取りする仕組みで、ローカルでは Node.js を立ててすんなり動きました。止まったのは本番です。WordPress は普通に表示できるのに、WebSocket の接続だけが成立しない。普通の fetch は通るのに、です。

原因は、最初の握手にありました。WebSocket は、いきなり WebSocket で始まるのではなく、まず普通の HTTP でつないで、Upgrade: websocket というヘッダーを載せて切り替えを申し込みます。サーバーが応じて初めて、双方向通信になる。VPS のようにリバースプロキシや WAF を自分で触れる環境なら、この Upgrade を転送する設定を書けばいいだけです。共用レンタルは違います。利用者が触れないプロキシや WAF が中間にいくつも挟まっていて、Upgrade を含むリクエストが、そのどれかで止まる。私の環境では、この握手が通りませんでした。2、3日いろいろ試して、共用レンタルで正面突破するのは無理だと見切りをつけました。WebSocket が悪いわけではありません。VPS や Cloudflare、Fly.io を前提にできるなら、いまでも第一候補です。

SSE は通った。なぜタイミングがそろわなかったのか

次に試したのが SSE です。サーバーからブラウザへ一方向にイベントを流し続ける仕組みで、HTTP に乗っているぶん、共用レンタルでも通りやすいと期待しました。実際、接続はできました。EventSource の通信が開いたまま、データも届く。WebSocket のように最初から失敗はしません。問題は、配信のタイミングでした。期待した間隔で届くこともあれば、しばらく無音のあと何件かまとめて来ることもある。同じコードを開き直しても、毎回そろうわけではない。

SSE は接続を開いたまま、サーバー側から少しずつ書き出します。ところが間に立つプロキシやバッファが、その少しずつをいったん溜めて、まとまってから流すことがあります。Nginx 配下なら X-Accel-Buffering: no で即時配信させる手がありますが、共用レンタルではサーバー全体の設定を変えられません。PHP 側で output_buffering を切ったり flush() を細かく入れたりしましたが、安定しませんでした。ニュース配信や進捗通知のように、多少前後しても困らない用途なら実用範囲かもしれません。チャットでは、送ったのに数十秒後にまとめて表示される、が致命的でした。

残った Long Polling は、なぜ動いたのか

残った選択肢が Long Polling でした。地味な仕組みですが、共用レンタルではこれがいちばん相性がよかった。動きはこうです。ブラウザがサーバーに新着はあるかと聞く。あればその場で返し、なければ一定時間待って、それでもなければ空で返す。受け取ったブラウザは、また次の問い合わせを始める。

Long Polling の問い合わせとレスポンスのループ

大事なのは、1回1回が完結した普通の HTTP リクエストだということです。WebSocket のような Upgrade はなく、SSE のように接続を開いたまま流し続ける必要もない。だから間にプロキシやキャッシュや WAF が挟まっていても、普通のページアクセスと同じ扱いで通っていく。実際に試したら、Xserver の共用レンタルでも素直に動きました。サーバー側(PHP)は、since より新しいメッセージがあるかを見て、なければ少し待ってもう一度見る、を制限時間まで繰り返します。

ブラウザ側は、レスポンスが返るたびに次を投げるループです。

これだけでも、共用レンタルで安定して動きました。WebSocket のような滑らかさはありませんが、数秒以内に届くので、待たされる感覚はあまりありません。

ただ投げ続けるだけでは、なぜまずいのか

短い間隔で投げ続けると、サーバーへの負担がじわじわ増えます。WordPress は1リクエストで読み込むものが多いので、待ち方は最初から考えておきたい。私が意識したのは、この4つです。

  • サーバー側の待ち時間を伸ばしすぎない。max_execution_time が30秒なら、待ちは15から20秒にして余裕を持たせる。ギリギリだと、たまにエラーになるユーザーが出て切り分けが面倒になります。
  • 新着がないとき、すぐ次を投げない。空レスポンスのあとに短いスリープ(コードの await sleep(60))を入れるだけで、リクエスト数の見え方が変わります。
  • タブが見えていないときは間引く。document.hidden を見て頻度を落とす。複数タブで開きっぱなしにする使い方で地味に効きます。
  • エラーが出たら、リトライ間隔を広げる。失敗が続くほど待ちを伸ばし、上限で頭打ちにする指数バックオフ。障害時に勝手に暴走しない安心感が違います。

3方式を、自分の環境で起きたことで並べる

方式 仕組み 私の環境での結果
WebSocket 双方向の常時接続(Upgrade で切り替え) 接続そのものが成立しなかった
SSE サーバーからの一方向ストリーミング 接続はできたが、配信タイミングが安定しない
Long Polling HTTP リクエストとレスポンスの繰り返し 共用レンタル上で安定して動いた

この表だけ見ると Long Polling が一番よく見えますが、そういう話ではありません。VPS や専用サーバー、Cloudflare Workers や Fly.io なら、WebSocket を選ぶ場面は多いはずです。あくまで Xserver の共用レンタル上の WordPress で、という前提での結果です。

即時性は、別のやり方でも作れる

Long Polling で気になるのは、WebSocket ほどの即時性が出ないことです。ただ、体験として、すべてを完全にリアルタイムにする必要はありません。自分が送ったメッセージは、サーバーの返答を待たずに先に画面へ並べてしまう。送信ボタンを押した瞬間に、自分のメッセージはもう表示されている。失敗が返ったときだけ、あとからエラー表示に差し替える。これを楽観的 UI 更新(Optimistic UI Update)と呼びます。相手から届くメッセージは Long Polling で数秒以内に取りに行く。業務システムでミリ秒の即時性が要件、というのでなければ、この体感で困る場面は意外と少ないです。

WordPress 7.0 のコアも、同じ場所に着地していた

この記事を書き直しているとき、WordPress 7.0 のリアルタイム共同編集の方針が公開されていました。Dev Note を読むと、同期方式のデフォルトが HTTP ポーリングになっていました。検討段階では WebRTC も候補だったものの、共用レンタルやネットワーク制限のある環境で動かないことを理由に却下した、と書かれています。WebSocket 対応のホスティングではフィルターで切り替えられるけれど、デフォルトはポーリング、という構成です。細かい背景は WordPress 7.0「Armstrong」リリースまとめ に書きました。共用レンタルで動くことを最優先したら、コア側もほぼ同じ場所に着地していた、というのは、少し心強い事実でした。

あなたなら、どの順で試しますか

同じ環境でチャットを入れるなら、最初から WebSocket だけに絞らず、Long Polling も視野に入れておくと切り分けが楽です。新しい方式から試して降りるのでも、枯れた方式から試して上がるのでも構いません。大事なのは、自分のサーバーで何が動いて何が動かないかを、早めに把握することです。

最後に、次にやる自分へのメモを兼ねて。検証中のエラーや挙動は、スクリーンショットでも走り書きでも、あとで読める形で残しておいたほうがいいです。私は今回それを残し損ねて、この記事も記憶に頼れる範囲までしか書けませんでした。当時の DevTools の画面があれば、もっと具体的に書けたはずなのに、と思います。あなたがこれから同じ環境にぶつかるなら、その一手間が、未来のあなたを助けてくれます。あなたなら、WebSocket と Long Polling、どちらから試しますか。

参考にした資料

Web Development
この記事を書いた人
rapls

WordPressのプラグインを作っているフリーランスエンジニアです。Web開発はもう6年以上。WordPress.orgで Rapls AI Chatbot、Thanks Mail for Stripe、Rapls PDF Image Creator、Prime Cache の4本を公開し、保守を続けながら、日本語ロケールの翻訳エディター(PTE)も務めています。このブログに書くのは、現場で自分が実際にハマって、調べて、直した話です。

raplsをフォローする
raplsをフォローする

コメント

タイトルとURLをコピーしました