他のクライアントからの変更や修正を監視したいRESTリソースがある場合、それを行うための最良の(そして最もRESTfulな)方法は何ですか?
そうするために私が持っていたアイデアの1つは、リソースが(まだ)存在しない場合にすぐに戻るのではなく、接続を開いたままにする特定のリソースを提供することです。たとえば、リソースが与えられた場合:
/game/17/playerToMove
このリソースの「GET」は、対戦相手が移動する番だと教えてくれるかもしれません。このリソースを継続的にポーリングして、移動する番がいつになるかを確認するのではなく、移動番号(たとえば、5)をメモして、次の移動を取得しようとする場合があります。
/game/17/move/5
「通常の」RESTモデルでは、このURLのGETリクエストは404(見つかりません)エラーを返すようです。ただし、代わりに、サーバーは対戦相手がプレイするまで接続を開いたままにしました彼の動き、すなわち:
PUT /game/17/move/5
その後、サーバーは、対戦相手がPUTしたコンテンツをそのリソースに返すことができます。これにより、必要なデータと、ポーリングを必要とせずに対戦相手が移動したときの一種の通知の両方が提供されます。
この種のスキームはRESTfulですか?それとも、ある種のREST原則に違反していますか?
提案されたソリューションは long polling のように聞こえますが、これは非常にうまく機能する可能性があります。
/game/17/move/5
を要求すると、移動5が完了するまで、サーバーはデータを送信しません。接続が切断された場合、またはタイムアウトが発生した場合は、有効な応答が得られるまで再接続するだけです。
これの利点は、非常に高速であるということです。サーバーが新しいデータを取得するとすぐに、クライアントはそれを取得します。また、接続の切断に対しても回復力があり、クライアントがしばらく切断された場合でも機能します(移動後、1時間後に/game/17/move/5
を要求し、データを即座に取得してから、move/6/
などに移動できます)。
長いポーリングの問題は、各「ポーリング」がサーバースレッドを拘束することです。これにより、Apacheなどのサーバーがすぐに壊れます(ワーカースレッドが不足するため、他のリクエストを受け入れることができません)。ロングポーリングリクエストを処理するには、専用のWebサーバーが必要です。Pythonモジュール twisted
( "イベント駆動型ネットワーキングエンジン")はこれには最適ですが、通常のポーリングよりも手間がかかります。
Jetty/Tomcatについてのあなたのコメントに答えて、私はJavaの経験がありませんが、どちらもApacheと同様のワーカースレッドシステムを使用しているようです。そのため、同じ問題が発生します。私は見つけました この投稿 これはまさにこの問題に対処しているようです(Tomcatの場合)
この記事 新しいHTTPヘッダー「When-Modified-After」を提案していることがわかりました。これは基本的に同じことを行います。サーバーは、リソースが変更されるまで接続を待機して開いたままにします。
タイムスタンプベースのアプローチよりもバージョンベースのアプローチの方が好きです。競合状態になりにくく、取得しているものについてもう少し情報が得られるからです。このアプローチについて何か考えはありますか?
目的のクライアントがWebブラウザーである場合は、接続を開いたままにしておくと、クライアント内の同じドメインへのブラウザー要求をアクティブにブロックできるため、404をお勧めします。ポーリングする頻度はクライアント次第です。