WebSockets与服务器发送事件/EventSource的比较

1195

WebSocketsServer-Sent Events都能够向浏览器推送数据。它们似乎是竞争性技术。它们之间有什么区别?在何时会选择其中一种?


5
不确定你是如何看待它们之间的竞争关系。其中一个是同步的,可以/将被用于近实时数据传输,而另一个是异步的,并将发挥完全不同的作用(有效地从服务器端应用程序发送类似 toast 的消息)。 - Brian Driscoll
32
我很喜欢SSE的一点是它很容易进行故障排除...只需使用curl打开到您的SSE服务器的请求。由于它只是基于HTTP的文本格式,所以很容易看出发生了什么。 - Sam
18
异步/同步 - 它们各自是什么?据我了解,两者都可以实现异步传输? - Dave Everitt
6
SSE 在 IE 上不起作用,需要使用 WebSockets。 - Tyler Gillies
3
请参考 MDN 的 SSE 页面,其中列出了几个 polyfill。Remy Sharp 的 polyfill 有 186 行,但可以将其削减到必要的部分,不过确实比 50 行多一些... ;) - oligofren
显示剩余4条评论
7个回答

1404

Websockets和SSE(服务器推送事件)都能够向浏览器推送数据,但它们不是竞争技术。

Websockets连接既可以向浏览器发送数据,也可以从浏览器接收数据。一个使用Websockets的好例子是聊天应用程序。

SSE连接只能向浏览器推送数据。在线股票报价或Twitter更新时间轴或信息流都是SSE可以受益的应用程序的好例子。

实际上,由于SSE可以做到的一切都可以用Websockets来完成,所以Websockets获得了更多的关注和爱,许多浏览器支持Websockets而不是SSE。

然而,对于某些类型的应用程序来说,这可能过度,而且后端使用SSE等协议可能更容易实现。

此外,SSE可以通过JavaScript在不支持它的旧版浏览器中进行填充。一些SSE polyfills的实现可以在Modernizr github页面上找到。

注意事项:

  • SSE受到打开连接数的限制,当打开各种选项卡时,这可能特别痛苦,因为限制是每个浏览器设置的非常低的数字(6)。该问题已在ChromeFirefox中标记为“不修复”。此限制是每个浏览器+域,这意味着您可以在所有选项卡上打开6个SSE连接到www.example1.com,并在www.example2.com上再打开6个SSE连接(感谢Phate)。
  • 只有WS可以传输二进制数据和UTF-8,SSE仅限于UTF-8。(感谢Chado Nihi)。
  • 一些企业防火墙在处理WebSockets时遇到麻烦(Sophos XG防火墙,WatchGuard,McAfee Web Gateway)。

HTML5Rocks提供了有关SSE的一些好信息。从该页面:

服务器推送事件(Server-Sent Events)与WebSockets的区别

为什么你会选择使用服务器推送事件而不是WebSockets呢?这是一个好问题。

服务器推送事件一直被放在阴影之中的原因之一是,后来的API(如WebSockets)提供了更丰富的协议来执行双向全双工通信。拥有双向通道对于游戏、消息应用程序以及需要双向近实时更新的情况更具吸引力。然而,在某些情况下,数据不需要从客户端发送。您只需要来自某些服务器操作的更新。一些例子包括朋友的状态更新、股票行情、新闻提要或其他自动化数据推送机制(例如更新客户端Web SQL数据库或IndexedDB对象存储)。如果您需要向服务器发送数据,则XMLHttpRequest始终是您的好帮手。

服务器推送事件通过传统的HTTP发送。这意味着它们不需要特殊的协议或服务器实现才能正常工作。另一方面,WebSockets需要全双工连接和新的Web Socket服务器来处理协议。此外,服务器推送事件具有各种特性,设计上WebSockets缺乏,例如自动重新连接、事件ID和发送任意事件的能力。


TLDR摘要:

服务器推送事件相对于Websockets的优势:

  • 通过简单的HTTP传输而不是自定义协议
  • 可以使用JavaScript进行polyfill,将SSE“回溯”到尚未支持它的浏览器。
  • 内置支持重新连接和事件ID
  • 更简单的协议
  • 不会出现企业防火墙进行数据包检查的问题

Websockets相对于服务器推送事件的优势:

  • 实时的双向通信。
  • 在更多浏览器中有原生支持

服务器推送事件的理想用例:

  • 股票行情流
  • Twitter动态更新
  • 向浏览器发送通知

服务器推送事件的注意事项:

  • 没有二进制支持
  • 最大打开连接限制

174
使用SSE完全可以实现聊天功能 - 您可以使用常规POST将消息发送到服务器。只有在实现类似Google Wave的聊天功能时才需要WebSocket。 - Kornel
189
使用SSE确实可以完成聊天和其他实时应用程序。但是,这需要通过“out of band”方式POST回复,也就是说,这不能由SSE协议控制,并且似乎不是一个好的例子来解释SSE和Websockets之间的区别。您可以使用基本HTTP轮询服务器每秒钟并POST新回复来实现聊天。这并不意味着这是最好/最优雅的方法。 - Alex Recarey
20
我认为pomeL的解决方案对于大多数情况来说是一个很好的折衷方案,因为JS可以通过AJAX POST将内容“推送”到服务器。根据我的经验,主要问题通常是JS需要轮询获取新信息,但SSE可以解决这个问题。 :D - Jacob Pritchett
21
@MattDiPasquale Wave在您输入时逐个发送每个按键,而不是一次性发送完整的消息。相比于WebSocket的约6个字节,为1个按键发送200个字节的POST开销将是浪费的。 - Kornel
23
说它们不是竞争技术,但又描述它们都可以用来实现类似的解决方案,这似乎有点奇怪。我会说这使它们成为竞争对手。 - Alex
显示剩余14条评论

153

根据caniuse.com的数据统计:

您可以使用仅客户端的polyfill将SSE协议扩展到许多其他浏览器上。但对于WebSockets协议来说这种情况不太可能发生。以下是一些EventSource polyfills:

如果您需要支持所有浏览器,请考虑使用像web-socket-jsSignalRsocket.io这样的库,它们支持多种传输方式,如WebSockets、SSE、Forever Frame和AJAX长轮询。这些通常还需要对服务器端进行修改。

可以从以下链接了解更多有关SSE协议的信息:

了解更多关于WebSockets的内容,请参考:

其他区别:

  • WebSockets支持任意二进制数据,SSE仅使用UTF-8。

3
我想指出,截至2016年,全球超过95%的用户都原生支持WebSockets。所有浏览器和设备已经支持WebSockets超过4年。如果不支持WebSockets,Socket.IO将退回到AJAX长轮询,并为您处理模拟WebSockets的复杂性,这使得支持率达到100%。如果你在2016年使用除了WebSockets以外的技术,那么你在使用过时的技术。 - Nick Steele
15
@NickSteele这句话是一种炒作的陈词滥调。如果旧标准可以胜任你的使用场景,那么依赖它们完全没有问题,并且这并不意味着什么已经过时了,只不过是不同的标准而已。例如,XHR仍然可以完成许多Fetch API无法完成的任务,因此它并不过时,只是不同而已。我过去曾经使用过WS,但从经验中知道,在噪声企业防火墙形式下,当WS不能被理解时,会遇到请求被阻止的麻烦。SSE非常高效地完成其工作,易于理解和实现,并且易于调试。对于我们的单向数据流,它非常完美。 - oligofren
@oligofren 不需要咒骂。如果某个东西被设计来替代以前的版本,并且在每个方面都更好,那么根据定义,旧方法已经过时了。就像最初的iPhone一样已经过时了,XHR也是如此。XHR发布之前,Firefox、Chrome、第一代iPhone、YouTube、Netflix、Facebook甚至MySpace都还不存在。WebSockets在近十年前取代了XHR。如果你在使用WS时遇到问题,那么导致问题的东西也已经过时了。没有任何借口可以这么落后。 - Nick Steele
11
用夸张的修辞来代替无用的废话吧 :-) WebSocket并不能替代XHR/HTTP,就像无人机不能替代送货车一样,它们有不同的使用场景。WebSocket不是HTTP,并且有不同的优势点。如果你试图将其作为HTTP的替代品(而且做得很差),最终只会在用户空间中重新实现HTTP。此外,你在暗示一些没有事实依据的东西:WebSocket只是一个支持服务器推送的双向协议,我从未看到任何设计文档提到它是作为任何东西的替代品而开发的。请问出处?年龄本身并不是一个因素。当有选择时,请选择检查所有要求的最简单实现。 - oligofren
8
仅仅两年前(2017年),我还在调试Node JS进程的堆转储,其中Socket.io代码导致IIS进程中出现了巨大的内存碎片,最终直接与Azure的Node团队交流。总复杂度并非免费的。如果您可以使用简单的20行脚本作为服务器上的依赖项,同时仍然能够为10万个客户端提供服务,我会选择这种方式。我喜欢WS能做到的事情,但在选择解决方案之前,请考虑您需要什么。 - oligofren
1
同时 (2021年): WebSockets 97%,SSE 96%。 - flix

34
2023年的情况与过去有所不同。
多年前,当IE仍然占据重要市场份额时,SSE的一个缺点是IE完全不支持(而WebSockets则在IE 10+上得到支持)。如今,根据caniuse.com的数据,在客户端方面,这两种技术的支持几乎相当:WebSockets为98.35%SSE为98.03%(这些统计数据适用于全球用户)。

从历史上看,SSE存在一个严重的限制,即每个域名只能建立6个连接(当在多个浏览器标签中打开yourapp.com时会出现问题),但这个问题在HTTP/2中已经不再是一个问题。所有现代浏览器都支持HTTP/2(全球用户占比97.16%),而在服务器端,HTTP/2+在过去几年中也超过了HTTP/1

在选择SSE和WebSockets之间需要考虑各种因素:

  • SSE的实现通常更简单,更容易进行测试/调试(可以使用简单的curl)。
  • WebSockets支持双向(全双工)通信。也就是说,如果需要双向通信,可以将SSE与AJAX结合使用。在这种情况下,WebSockets通常被认为是更简单的选择,但我认为这样的概括可能会误导人,因为它在很大程度上取决于应用程序的类型、设计方式和所使用的技术。
  • SSE仅支持UTF-8文本消息,而WebSockets还可以传输二进制数据。
  • 我们可以在客户端使用内置的EventSource API来使用SSE。然而,现在人们经常选择使用库,比如流行的fetch-event-source,它是一个与EventSource兼容的SSE替代方案,提供了额外的功能,比如自定义头部、更高级的重试策略、当浏览器最小化时自动关闭连接等。
  • 从实际角度考虑,我还建议研究一下你的应用服务器对这些技术的支持程度。请注意,有些技术依赖于额外的模块和/或库。你可能想看一些示例,或者快速构建一个原型。

为什么在HTTP/1中的6个连接限制成为问题?我不明白它与普通请求有何不同。一旦连接完成,难道它不会自动终止并释放吗?为什么它比常规的HTTP调用更成问题呢? - COOKIE
1
@COOKIE 正常的请求都是很短的 - 浏览器发送一个请求,服务器返回一个响应。如果浏览器突然需要发出50个请求,它会简单地将它们排队,(通常)它们很快就会被处理。然而,使用SSE,您拥有一个永久的专用连接(想象一个具有“无止境”响应的请求)。如果abc.com使用1个SSE连接,但用户在7个以上的浏览器标签中打开了abc.com,使用旧的HTTP/1协议,用户将会遇到问题。 - at54321
谢谢您的快速回复。我过于关注openAI使用SSE的方式,他们通过流式传输文本而不是一次性发送。在这种情况下,我认为它们在连接使用方面应该是相同的?我没有考虑到SSE的其他应用,比如通知。 - COOKIE
SSE的另一个缺点在于EventSource接口。除了urlwithCredentials标志之外,您无法设置其他任何内容。 因此,如果您的用例需要发送附加数据,您必须将其添加到URL查询字符串中,或者使用第三方实现,如fetch-event-source。您还无法控制重试策略。EventSource将以固定间隔(由服务器定义)进行重试。 - MayThrow
1
@rzr 感谢你提出这个问题。确实,内置的 EventSource 存在一些限制,现在很多人都使用 fetch-event-source 作为一个更强大的替代方案。这一点非常重要,所以我更新了我的帖子。 - at54321

23

WebSocket VS SSE


WebSocket - 这是一种协议,它在单个TCP连接上提供全双工通信通道。 例如,在服务器和浏览器之间进行双向通信。由于该协议比较复杂,因此服务器和浏览器必须依赖websocket库,其中包括 socket.io

Example - Online chat application.

SSE(服务器推送事件) - 在服务器推送事件中,通信仅从服务器到浏览器进行,浏览器无法向服务器发送任何数据。这种通信主要用于只需要显示更新数据的情况下,服务器会在数据更新时发送消息。例如,服务器向浏览器的单向通信。由于该协议较为简单,因此无需依赖外部库,JavaScript本身提供EventSource接口以接收服务器发送的消息。

Example - Online stock quotes or cricket score website.

2
在浏览器端,WebSockets已经内置于浏览器中,因此无需使用外部库。 - Scott Stensland

19

Opera、Chrome和Safari支持SSE, Chrome和Safari支持SharedWorker内的SSE。 Firefox支持XMLHttpRequest的readyState交互,因此我们可以为Firefox制作EventSource polyfil。


10

需要注意的一点:
我曾与公司防火墙遇到过WebSockets相关的问题。(使用HTTPS有助于解决,但并非总是有效。)

详情请参见:https://github.com/LearnBoost/socket.io/wiki/Socket.IO-and-firewall-software, https://github.com/sockjs/sockjs-client/issues/94

假设使用Server-Sent Events不会出现这样的问题,但我不确定。

话虽如此,WebSockets非常有趣。我有一个小型网络游戏,使用了WebSockets(通过Socket.IO实现)。(http://minibman.com)


1
我也曾经遇到过企业防火墙的问题。 - oligofren
2
我所见过的Server-Sent Events的一个问题是,一些代理/防火墙可能会阻止它,因为它没有Content-Length头。 - Drew LeSueur
此外,如果未将X-Accel-Buffering头设置为no,则Nginx也可以阻止它。 - TrojanName

9

它们在语义上不同。

WebSocket 具有“双向数据流”的本机语义含义。

而 SSE 具有“发布-订阅模式”或“请求-响应模式”的本机语义含义,尽管响应是一个数据流。

当然,您可以自己在 WebSocket 上实现一层“发布-订阅模式”或“请求-响应模式”的功能。


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