服务器发送事件(SSE) vs. WebSockets


在开发实时 Web 应用程序时,WebSockets可能是您首先想到的。但是,服务器发送事件 (SSE) 是一种更简单的替代方案,通常更胜一筹。

 
WebSockets
WebSockets支持在浏览器和服务器之间创建双向 低延迟通信通道。
这使得它们在某些场景中非常理想,例如多人游戏,其中通信是双向的,因为浏览器和服务器始终在通道上发送消息,并且要求这些消息以低延迟传递.
在第一人称射击游戏中,浏览器可以持续传输玩家的位置,同时从服务器接收所有其他玩家位置的更新。此外,我们绝对希望以尽可能少的开销传递这些消息,以避免游戏感觉迟缓。
这与传统的HTTP[url=https://en.wikipedia.org/wiki/Request%E2%80%93response]请求-响应模型[/url]相反,其中浏览器始终是发起通信的一方,并且由于建立TCP 连接HTTP 标头,每条消息都有很大的开销。
但是,许多应用程序没有这么严格的要求。即使在实时应用程序中,数据流通常也是不对称的:服务器发送大部分消息,而客户端主要只是侦听,偶尔发送一些更新。例如,在聊天应用程序中,用户可能连接到许多房间,每个房间都有数十或数百名参与者。因此,收到的消息量远远超过发送的消息量。
WebSocket 有什么问题?
WebSockets 有一个主要缺点:它们不能在 HTTP 之上工作,至少不能完全工作。他们需要自己的 TCP 连接。他们仅使用 HTTP 来建立连接,然后将其升级为可以使用 WebSocket 协议的独立 TCP 连接。
这似乎没什么大不了的,但这意味着WebSockets 不能从任何 HTTP 特性中受益。那是:

  • 不支持压缩
  • 不支持 HTTP/2 多路复用
  • 代理的潜在问题
  • 无法防止跨站点劫持

至少,这是 WebSocket 协议刚发布时的情况。如今,有一些补充标准试图改善这种情况。让我们仔细看看目前的情况。
 
服务器发送的事件SSE
服务器发送事件使服务器能够随时向客户端发送低延迟推送事件。它们使用一个非常简单的协议,该协议是HTML 标准的一部分,每个浏览器都支持
与 WebSocket 不同,服务器发送的事件只有一种方式流动:从服务器到客户端。这使得它们不适合一组非常特定的应用程序,即那些需要双向和低延迟通信通道的应用程序,例如实时游戏。然而,这种权衡也是它们相对于 WebSockets 的主要优势,因为作为单向,服务器发送事件在 HTTP 之上无缝工作,不需要自定义协议. 这使他们能够自动访问 HTTP 的所有功能,例如压缩或 HTTP/2 多路复用,使其成为大多数实时应用程序的非常方便的选择,在这些应用程序中,大部分数据是从服务器发送的,而由于 HTTP 标头,请求中的少量开销是可以接受的。
该协议非常简单。它使用以下text/event-stream形式的 Content-Type 和消息:

data: First message

event: join
data: Second message. It has two
data: lines, a custom event type and an id.
id: 5

: comment. Can be used as keep-alive

data: Third message. I do not have more data.
data: Please retry later.
retry: 10

每个事件由两个空行 ( \n) 分隔,并由各种可选字段组成。

  • data字段可以重复以表示消息中的多行,不出所料地用于事件的内容。
  • event字段允许指定自定义事件类型,正如我们将在下一节中展示的,可用于在客户端触发不同的事件处理程序。
  • 其他两个字段id和retry用于配置自动重新连接机制的行为。这是服务器发送事件最有趣的功能之一。它确保 当连接被服务器断开或关闭时,客户端将自动尝试重新连接,而无需任何用户干预。
  • retry字段用于指定在尝试重新连接之前等待的最短时间(以秒为单位)。它也可以由服务器在关闭客户端连接之前立即发送,以在连接太多客户端时减少其负载。
  • id字段将标识符与当前事件相关联。重新连接时,客户端将使用Last-Event-IDHTTP 标头将上次看到的 id 传输到服务器。这允许从正确的点恢复流。
  • 最后,服务器可以通过返回HTTP 204 No Content响应来完全停止自动重新连接机制。

 
比较代码
在本节中,我们将使用 Server-Sent Events 和 WebSockets 实现一个简单的服务。这应该使我们能够比较这两种技术。我们将了解开始使用每个功能是多么容易,并手动验证前几节中讨论的功能。
我们将使用 Python 作为后端,Caddy 作为反向代理,当然还有几行 JavaScript 作为前端。
为了使我们的示例尽可能简单,我们的后端将仅包含两个端点,每个端点都流式传输一个唯一的随机数序列。它们将可以从 服务器发送的事件以及从/sse1WebSockets访问。虽然我们的前端将由一个 文件组成,但有一些 JavaScript 可以让我们启动和停止 WebSockets 和服务器发送事件连接。/sse2/ws1/ws2index.html
此示例的代码可在 GitHub 上找到

更多点击标题