单向数据流
当我们使用实时数据设计Web应用程序时,我们都需要考虑如何将数据从服务器传递到客户端。默认答案通常是使用“WebSockets”,除了这个还有其他更好的方法吗?
答案是有的,让我们比较三种不同的方法:Long polling(长轮询),WebSockets和Server-Sent Events(服务器发送事件,简称SSE),了解他们实际使用的局限性,答案可能会让你大吃一惊。
当涉及从服务器到客户端的数据传递时,我们仅限于两种通用方法:客户端拉取或服务器推送。当浏览器中的网站向服务器询问数据时,这称为客户端拉取。相反,当服务器主动将更新推送到您的网站时,它称为服务器推送。
如今,有几种方法可以实现这些功能:
长/短轮询(客户拉动)WebSockets(服务器推送)服务器发送事件(服务器推送)。
长轮询
客户端要求服务器提供数据,服务器没有数据,在发送响应之前会等待一段时间:
如果在等待期间弹出某些东西,服务器会发送它并关闭请求;如果没有要发送的内容并且达到最大等待时间,则服务器发送没有数据的响应;在以上这两种情况下,客户端都会打开下一个数据请求;每个轮询请求和响应都是完整的HTTP消息,并在消息框架中包含一整套HTTP标头。在我们的频繁消息频繁的情况下,标题实际上代表了传输数据的较大百分比。
服务器响应后,在客户端发送下一个请求之前,它不能再向客户端发送数据。
虽然可以通过使用持久HTTP连接可以避免许多轮询请求来避免这种情况,但是相应地计算所有组件在短时间内轮询以保持连接活动是很麻烦的技术。
下降负载不足的长轮询客户端(或服务器)自然倾向于以消息延迟为代价降低性能。发生这种情况时,推送到客户端的事件将排队。
长轮询请求需要保持挂起状态,直到服务器有东西发送到客户端。如果代理服务器长时间处于空闲状态,这可能会导致连接关闭。
如果HTTP连接上同时发生持久响应,则会发生多路复用情况。
WEBSOCKETS
WebSockets是一种先进的技术,可以在用户的浏览器和服务器之间打开交互式通信会话。使用API,可以将消息发送到服务器并接收事件驱动的响应,而无需轮询服务器以进行回复。
HTTP和WebSockets都位于OSI模型的应用层,因此依赖于第4层的TCP。
通常,WebSockets和代理存在一些不同的问题:
在服务器和客户端上实现自定义多路复用过于复杂,无法使套接字在指定的业务案例中有用。
当你的服务器过载,并且你需要创建新实例并根据软件的实现终止旧实例时,“重新连接”所采取的操作可能会触发大量的刷新链和新的数据请求,从而导致系统过载,需要在服务器和客户端上维护WebSockets。如果当前的服务器遇到高负载,则无法将套接字连接移动到其他服务器,必须关闭并重新打开它们。
这通常由前端HTTP代理处理,这些代理无法由WebSockets所需的TCP代理处理,容易受到DOS攻击。
重新发明轮子:使用WebSockets,必须处理许多自己在HTTP中处理的问题。
SSE
EventSource接口用于接收服务器发送的事件。它通过HTTP连接到服务器,并以文本/事件流格式接收事件,而不关闭连接。
SSE独特功能:
连接流来自服务器并且是只读的。它们使用常规HTTP请求进行持久连接,而不是特殊协议。如果连接断开,EventSource将触发错误事件并自动尝试重新连接。服务器还可以在客户端尝试重新连接之前控制超时。客户端可以发送带有消息的唯一ID。当客户端在断开连接后尝试重新连接时,它将发送最后一个已知ID。然后,服务器可以看到客户端错过n多少条消息,并在重新连接时发送了错过消息的积压。SSE不仅是提供快速更新的方法,而且在移动设备的优化方面,更有优势。就服务器端实现而言,它与轮询没有太大区别,在客户端上,它比轮询简单得多,因为它需要初始订阅和分配事件处理程序,与WebSockets的管理方式非常相似。