40

如果有一个 REST 资源我想监视来自其他客户端的更改或修改,那么最好(也是最 RESTful)的方法是什么?

我这样做的一个想法是通过提供特定资源来保持连接打开,而不是在资源不(尚)存在时立即返回。例如,给定资源:

/game/17/playerToMove

对此资源的“GET”可能会告诉我轮到我的对手移动了。与其不断轮询此资源以找出轮到我移动的时间,我可能会记下移动编号(例如 5)并尝试检索下一步:

/game/17/move/5

在“正常”REST 模型中,对此 URL 的 GET 请求似乎会返回 404(未找到)错误。但是,如果相反,服务器保持连接打开,直到我的对手下棋,即:

PUT /game/17/move/5

然后服务器可以返回我的对手放入该资源的内容。这既可以为我提供我需要的数据,也可以为我的对手何时移动而不需要轮询提供一种通知。

这种方案是 RESTful 的吗?还是它违反了某种 REST 原则?

4

3 回答 3

28

您提出的解决方案听起来像long polling,可以很好地工作。

您将请求/game/17/move/5并且服务器不会发送任何数据,直到移动 5 完成。如果连接断开或超时,您只需重新连接,直到获得有效响应。

这样做的好处是它非常快——只要服务器有新数据,客户端就会得到它。它对断开的连接也具有弹性,并且如果客户端断开连接一段时间(您可以/game/17/move/5在它被移动后一小时请求并立即获取数据,然后继续move/6/等等)

长轮询的问题是每个“轮询”都会占用一个服务器线程,这会很快破坏像 Apache 这样的服务器(因为它用完了工作线程,所以不能接受其他请求)。你需要一个专门的网络服务器来服务长轮询请求。Python 模块twisted(一个“事件驱动的网络引擎”)非常适合这个,但它比常规轮询工作更多。

在回答您关于 Jetty/Tomcat 的评论时,我对 Java 没有任何经验,但似乎它们都使用与 Apache 类似的工作线程池系统,所以它会有同样的问题。我确实找到了这篇似乎正好解决了这个问题的帖子(对于 Tomcat)

于 2009-01-02T04:39:44.973 回答
2

我发现这篇文章提出了一个新的 HTTP 标头“When-Modified-After”,它基本上做同样的事情——服务器等待并保持连接打开,直到资源被修改。

我更喜欢基于版本的方法而不是基于时间戳的方法,因为它不太容易出现竞争条件,并且可以为您提供更多关于您正在检索的信息的信息。对这种方法有什么想法吗?

于 2009-01-02T03:43:17.147 回答
2

如果您的预期客户端是 Web 浏览器,我建议使用 404,因为保持连接打开可以主动阻止客户端中对同一域的浏览器请求。多久轮询一次取决于客户。


2021 年编辑:上面的答案是在 2009 年,以供参考。

今天,我建议使用带有推送通知的 WebSocket 接口。

或者,在上述建议中,我可能建议保持连接 500-1000 毫秒,并在返回 404 之前在服务器上检查两次,以减少在客户端创建多个连接的开销。

于 2009-01-02T03:54:18.030 回答