监视 REST 资源更改的 RESTful 方式是什么?
如果我想要监视某个 REST 资源以了解其他客户端的更改或修改,那么最好(也是最 RESTful)的方法是什么?
我这样做的一个想法是提供特定的资源来保持连接打开,而不是在资源(尚)不存在时立即返回。 例如,给定资源:
/game/17/playerToMove
对该资源的“GET”可能会告诉我轮到我的对手移动了。 我可能会记下移动编号(例如 5)并尝试检索下一个移动,而不是不断轮询此资源来找出何时轮到我移动:
/game/17/move/5
在“正常”REST 模型中,似乎是对此 URL 的 GET 请求将返回 404(未找到)错误。 然而,如果相反,服务器保持连接打开,直到我的对手下棋,即:
PUT /game/17/move/5
那么服务器可以返回我的对手放入该资源的内容。 这既可以为我提供所需的数据,也可以在我的对手移动时发出某种通知,而无需进行轮询。
这种方案是 RESTful 的吗? 或者它是否违反了某种 REST 原则?
If there is a REST resource that I want to monitor for changes or modifications from other clients, what is the best (and most RESTful) way of doing so?
One idea I've had for doing so is by providing specific resources that will keep the connection open rather than returning immediately if the resource does not (yet) exist. For example, given the resource:
/game/17/playerToMove
a "GET" on this resource might tell me that it's my opponent's turn to move. Rather than continually polling this resource to find out when it's my turn to move, I might note the move number (say 5) and attempt to retrieve the next move:
/game/17/move/5
In a "normal" REST model, it seems a GET request for this URL would return a 404 (not found) error. However, if instead, the server kept the connection open until my opponent played his move, i.e.:
PUT /game/17/move/5
then the server could return the contents that my opponent PUT into that resource. This would both provide me with the data I need, as well as a sort of notification for when my opponent has moved without requiring polling.
Is this sort of scheme RESTful? Or does it violate some sort of REST principle?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您提出的解决方案听起来像长轮询,效果非常好。
您将请求
/game/17/move/5
,服务器将不会发送任何数据,直到第 5 步完成。 如果连接断开,或者超时,您只需重新连接,直到获得有效响应。这样做的好处是速度非常快——一旦服务器有新数据,客户端就会得到它。 它还可以适应断开的连接,并且在客户端断开连接一段时间后也可以工作(您可以在移动后一小时请求
/game/17/move/5
并立即获取数据,然后移动到move/6/
等)长轮询的问题是每个“轮询”都会占用一个服务器线程,这会很快破坏 Apache 等服务器(因为它耗尽了工作线程,所以可以不接受其他请求)。 您需要一个专门的网络服务器来服务长轮询请求。Python 模块
twisted
< /a> (“事件驱动的网络引擎”)对此非常有用,但它比常规轮询需要更多工作。.在回答您关于 Jetty/Tomcat 的评论时,我没有任何 Java 经验,但它似乎它们都使用与 Apache 类似的工作线程池系统,所以它也会有同样的问题。 我确实找到了这篇文章,它似乎解决了正是这个问题(对于Tomcat)
Your proposed solution sounds like long polling, which could work really well.
You would request
/game/17/move/5
and the server will not send any data, until move 5 has been completed. If the connection drops, or you get a time-out, you simply reconnect until you get a valid response.The benefit of this is it's very quick - as soon as the server has new data, the client will get it. It's also resilient to dropped connections, and works if the client is disconnected for a while (you could request
/game/17/move/5
an hour after it's been moved and get the data instantly, then move ontomove/6/
and so on)The issue with long polling is each "poll" ties up a server thread, which quickly breaks servers like Apache (as it runs out of worker-threads, so can't accept other requests). You need a specialised web-server to serve the long-polling requests.. The Python module
twisted
(an "an event-driven networking engine") is great for this, but it's more work than regular polling..In answer to your comment about Jetty/Tomcat, I don't have any experience with Java, but it seems they both use a similar pool-of-worker-threads system to Apache, so it will have that same problem. I did find this post which seems to address exactly this problem (for Tomcat)
如果您的目标客户端是 Web 浏览器,我建议使用 404,因为保持连接打开可以主动阻止客户端中对同一域的浏览器请求。 轮询的频率取决于客户端。
2021 年编辑:上面的答案是在 2009 年,以供参考。
今天,我建议使用带有推送通知的 WebSocket 接口。
或者,在上面的建议中,我可能建议将连接保持 500-1000 毫秒,并在返回 404 之前在服务器上检查两次,以减少在客户端创建多个连接的开销。
I'd suggest a 404, if your intended client is a web browser, as keeping the connection open can actively block browser requests in the client to the same domain. It's up to the client how often to poll.
2021 Edit: The answer above was in 2009, for context.
Today, I would suggest using a WebSocket interface with push notifications.
Alternatively, in the above suggestion, I might suggest holding the connection for 500-1000ms and check twice at the server before returning the 404, to reduce the overhead of creating multiple connections at the client.
我发现这篇文章< /a> 提出一个新的 HTTP 标头“When-Modified-After”,本质上做同样的事情——服务器等待并保持连接打开,直到资源被修改。
我更喜欢基于版本的方法而不是基于时间戳的方法,因为它不太容易出现竞争条件,并且可以为您提供有关正在检索的内容的更多信息。 对这种方法有什么想法吗?
I found this article proposing a new HTTP header, "When-Modified-After", that essentially does the same thing--the server waits and keeps the connection open until the resource is modified.
I prefer a version-based approach rather than a timestamp-based approach, since it's less prone to race conditions and gives you a little more information about what it is you're retrieving. Any thoughts to this approach?