Jetty上的持久推送与Comet长轮询?

3
我正在尝试创建一个Jetty servlet,允许客户端(Web浏览器、Java客户端等)从Web服务器获取广播通知。
通知应以JSON格式发送。
我的第一个想法是使客户端发送长轮询请求,当有可用的通知时,使用Jetty的Continuation API进行响应,然后重复此过程。
这种方法的问题在于我错过了两个请求之间发生的所有通知。
我找到的唯一解决方案是在服务器上缓冲事件,并使用时间戳机制重新传输丢失的通知,这有效,但看起来对于它所做的事情来说相当繁重...
你有什么更优雅的解决方案吗?
谢谢!
4个回答

3

抱歉打扰了,但我相信许多人将会遇到这个帖子和已接受的答案,但我认为它过时了,甚至可以说是误导性的。

按照优先顺序,我的意见如下:

1)现在最好的解决方案是WebSockets。我个人有在企业应用中引入WebSockets的经验。所有主要的浏览器(Chrome,Firefox,IE - 按字母顺序 :)) 都原生支持WebSockets。所有主要的服务器 / servlets(IIS,Tomcat,Jetty)都是一样的,而且在Java中有很多实现JSR 356 API的框架。确实存在代理问题,特别是在云部署中。但WebSockets要求得到高度关注,所以NginX早在1.5年前就支持它们了。无论如何,安全的“wss”协议可以在99.9%(不是100%,只是为了保险起见,我自己从未遇到)情况下解决代理问题。

2)长轮询可能是第二好的解决方案,“可能”部分归因于“短轮询”可替代。当谈到长轮询时,我的意思是来自客户端对服务器重复请求,并在任何数据可用时立即响应的请求。因此,一个轮询可以在几毫秒内完成,另一个轮询可能要等到最大等待时间。 请确保将轮询时间限制在小于2分钟的某个值,否则通常需要在客户端管理超时错误。我建议将轮询时间限制在几十秒钟左右。 确保一次轮询完成之后(及时或在此之前),它会立即重复(但最好建立一些简单的协议,并给予服务器一个机会告诉客户端“挂起”)。 长轮询的缺点,我认为这正义继续列出列表的原因,是它拥有浏览器允许每个页面与服务器建立的仅有的几个连接(4、8个?还不是很多),因此它可能会消耗约12%到25%的您网站客户端流量资源。

3)短轮询并不被许多人所喜爱,但有时我更喜欢它。其主要缺点是,在建立新连接时对浏览器和服务器的负载很高。然而,我认为如果适当地使用连接池,则这种开销要小得多,不像第一眼看起来那么糟糕。

4)HTTP流,无论是通过IFrame还是XHR流式传输页面,都是我认为非常糟糕的解决方案,因为它就像是所有其他方案的缺点和更多缺点的积累:

  • 您将保持打开的连接(浏览器和服务器资源);

  • 您仍将消耗可用客户端流量总限制;

  • 最糟糕的是:您需要设计/实现(或重用设计/实现)实际内容传递,以便能够区分新内容和旧内容(无论是在推动脚本还是跟踪累积内容的长度)。请不要这样做。

更新(2019年2月20日)

如果WebSockets不是一种选择,则Server Sent Events是我认为的第二好选择 - 在这里,浏览器为您实现了HTTP流。


我不理解你对于“HTTP流”所给出的答案。你能否更明确地说明这个选项的优缺点呢?它似乎相当于一个单一的长轮询连接(而不是多个连接),因此如果有什么问题,它听起来比长轮询更好。 - Gili
HTTP流媒体大致工作方式如下:从客户端打开一些GET请求,在服务器上保持响应的输出流,并定期向其中写入数据。在客户端看来,你将监听和处理进度事件。每次有进度更新时,你需要知道新到达的数据是什么。直接询问这个问题是不可能的,但你需要保存到目前为止所有的数据(也不能清除),并在每个进度事件中计算数据上一个状态和当前状态之间的差异。定期需要重置所有内容以清空内存。 - GullerYA
在长轮询(long polling)的方式中,没有并发的多个连接,但是,在每个服务器端消息迭代(每次连接被“消耗”时,如果你想这样说的话),你都会重新打开连接。仍然从客户端和服务器的角度来看,代码更加清晰、易于维护。顺便说一下,如果WebSockets不可用,我认为Server Sent Events是第二好的选择-有效地实现了浏览器在较低层次上对HTTP流的处理。 - GullerYA
在我看来,HTTP流式传输(分块编码)似乎不必按照你所描述的方式实现。你可以在其上实现幂等协议,以便接收到的任何事件都包含绝对值。这样,您就不必保留任何状态并计算数据最后状态和当前状态之间的差异。 - Gili
如果你所说的“on top of it”是指自己编写一些低级库,以抽象化地处理整个“从开头获取完整数据,删除先前已知数据并仅输出差异”的过程,那么没问题。但是,你仍然需要在某个地方编写这些内容。如果你的意思是它可以完全不同地实现 - 那么欢迎你进行尝试,并向我和其他人传授如何做到这一点 :) - GullerYA

3

HTTP�媒体�对比HTTP长轮询更好。WebSockets是一个更好的解决方案。

WebSockets�供了第一个标准化的��全�工解决方案,用�在Web上���时通信,�以在任何客户端(�一定是Web�览器)和�务器之间进行通信。我认为WebSockets是最好的选择,因为它们是一�技术,将会�续�展�得到支�和需求,并且�会在使用�和�行度上�长。它们也�常酷�。

似�有Java的几个WebSocket客户端和Jetty也支�WebSockets。


@leggeter:我同意WebSockets本来是最适合这项工作的,但不幸的是,目前我无法承受它们有限的浏览器支持。不过我会看一下HTTP流传输。谢谢! - nbarraille
我强烈推荐您阅读@katana关于[WebSocket readiness](https://dev59.com/JWw15IYBdhLWcg3wu-I9#6442488)的优秀答案。 WebSockets具备回退功能,这意味着99%的Web浏览器都可以使用WebSocket连接。 - leggetter
Web套接字在代理中的支持不够好。如果您的客户端和服务器之间有代理,则可能需要使用备用方法。 - ijw
如果您使用SSL(wss://)WebSocket连接,那么根据我的经验,处理大量Pusher支持呼叫的情况下,该连接将被建立。我认为人们普遍误解WebSockets与代理不兼容的主要原因是开发人员在开发时没有使用SSL连接,因此没有检查是否能够解决问题。不幸的是,我目前还无法证明这一点。 - leggetter

2
我之前使用 Atmosphere 框架进行 Http 流传输,效果很好。请访问 Comet, Streaming。如果您查看 Atmosphere 教程,会发现他们提供了多个示例。

1

你可能想要查看CometD中是如何实现的:http://cometd.org。或者你甚至可以考虑使用这个工具,而不必重新发明轮子。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接