2009-01-02 17 views
35

S'il y a une ressource REST que je veux surveiller pour des changements ou des modifications d'autres clients, quelle est la meilleure façon (et la plus RESTful) de le faire? Une idée que j'ai eu pour le faire est de fournir des ressources spécifiques qui garderont la connexion ouverte plutôt que de revenir immédiatement si la ressource n'existe pas (encore). Par exemple, compte tenu de la ressource:Qu'est-ce qu'un moyen RESTful de surveiller une ressource REST pour les changements?

/game/17/playerToMove 

un « GET » sur cette ressource pourrait me dire que c'est le tour de mon adversaire de se déplacer. Au lieu de vote sans cesse cette ressource pour savoir quand il est mon tour de bouger, je pourrais noter le numéro de déplacement (par exemple 5) et tenter de récupérer le mouvement suivant:

/game/17/move/5 

Dans un modèle « normal » REST, il semble qu'une requête GET pour cette URL renverrait une erreur 404 (non trouvée). Toutefois, si au contraire, le serveur a gardé la connexion ouverte jusqu'à ce que mon adversaire a joué son mouvement, i.e. .:

PUT /game/17/move/5 

le serveur pourrait retourner le contenu que mon adversaire mise en cette ressource. Cela me fournirait à la fois les données dont j'ai besoin, ainsi qu'une sorte de notification pour savoir quand mon adversaire s'est déplacé sans avoir besoin d'interroger.

Est-ce que ce genre de schéma RESTful? Ou est-ce que cela viole une sorte de principe REST?

+1

"Quelle est la façon _rest_ de faire cela, Scrappy?" –

+0

Vous pouvez utiliser une interrogation longue ou combiner REST avec un service Websocket, qui envoie les événements au client. – inf3rno

Répondre

24

Votre solution proposée ressemble à long polling, ce qui pourrait très bien fonctionner.

Vous demanderiez /game/17/move/5 et le serveur n'enverra aucune donnée, jusqu'à ce que le déplacement 5 soit terminé. Si la connexion diminue ou si vous obtenez un délai d'attente, vous vous reconnectez simplement jusqu'à ce que vous obteniez une réponse valide. L'avantage de ceci est qu'il est très rapide - dès que le serveur a de nouvelles données, le client l'obtiendra. Il est également résistant aux connexions interrompues et ne fonctionne que si le client est déconnecté pendant un certain temps (vous pouvez demander /game/17/move/5 une heure après qu'il a été déplacé et obtenir les données instantanément, puis déplacez sur move/6/ et ainsi de suite)

Le problème avec longue l'interrogation est que chaque "interrogation" lie un thread de serveur, ce qui brise rapidement des serveurs comme Apache (puisqu'il ne contient plus de threads de travail, il ne peut donc pas accepter d'autres requêtes). Le module Python twisted (un "moteur de gestion de réseau basé sur les événements") est parfait pour cela, mais c'est plus de travail que les sondages réguliers.En réponse à votre commentaire à propos de Jetty/Tomcat, je n'ai aucune expérience avec Java, mais il semble qu'ils utilisent tous les deux un système similaire à Apache, ce qui pose le même problème . J'ai trouvé this post qui semble résoudre exactement ce problème (pour Tomcat)

+0

J'utilise Jetty comme Java conteneur de servlet. Cela semble fonctionner très bien pour les «longs scrutins». A-t-il les mêmes problèmes qu'Apache (à savoir, à court de threads de travail)? Qu'en est-il de Tomcat? – Ross

+0

Pour éviter d'attacher des threads, vous pouvez utiliser un gestionnaire HTTP asynchrone asp.net. Cela renvoie le thread au pool de threads. –

2

J'ai trouvé this article en proposant un nouvel entête HTTP, "When-Modified-After", qui fait essentiellement la même chose - le serveur attend et maintient la connexion ouverte jusqu'à ce que la ressource soit modifiée. Je préfère une approche basée sur la version plutôt qu'une approche basée sur l'horodatage, car elle est moins sujette aux conditions de course et vous donne un peu plus d'informations sur ce que vous récupérez. Des pensées à cette approche?

+0

L'approche basée sur la version utiliserait l'en-tête HTTP ETag. http://en.wikipedia.org/wiki/HTTP_ETag – Chase

2

Je suggérerais un 404, si votre client cible est un navigateur Web, car maintenir la connexion ouverte peut bloquer activement les demandes de navigateur dans le client au même domaine. C'est au client de décider à quelle fréquence interroger.

+0

C'est un peu une mauvaise utilisation de l'erreur (comment détecter un 404 réel parce que vous avez demandé/jeu/x14 pas/jeu/14) .. Retour {'erreur' : 'pas de nouveau contenu'} ou quelque chose serait moins problématique .. – dbr

+3

non, parce que jusqu'à l'étape 14 a été faite, la ressource n'existe pas ... c'est un vrai 404. – Tracker1