使用Websocket API代替REST API?

112

我有一个应用程序,其主要功能通过Websockets或长轮询实时工作。

然而,大部分站点都是以RESTful的方式编写的,这对于未来的应用程序和其他客户端非常好。但是,我正在考虑将所有站点功能转换为websocket API,远离REST。这将使我更容易地将实时功能集成到站点的所有部分中。这样做是否会使构建应用程序或移动客户端更加困难?

我发现一些人已经在做类似的事情:SocketStream


2
@Stegi 长轮询作为后备方案已经足够好了,我并不是特别担心这个问题。 - Harry
3
哈利,现在已经过去了7年,你对此有何感受?我想知道,因为我也想走这条路。@Harry - Dmitry Kudryavtsev
3
我最终没有这样做。传统方法对我来说效果很好,而且并不困难。 - Harry
10个回答

110

虽然其他回答也有一定的价值并提出了一些好的观点,但是我会反其道而行之,并同意你的看法——通过Websockets来实现不只是实时功能的迁移非常诱人。

我正在认真考虑将我的应用从RESTful架构转移到更多采用基于Websockets的RPC风格。这不是一个“玩具应用程序”,我也不仅谈论实时特性,所以我有保留意见。但我认为采用这种方式会带来很多好处,可能会成为一个非常出色的解决方案。

我的计划是使用DNodeSocketIOBackbone。借助这些工具,我的Backbone模型和集合可以通过简单地调用函数的RPC风格在客户端和服务器之间传递。不再需要管理REST端点、序列化/反序列化对象等等。虽然我还没有使用socketstream,但它看起来值得一试。

在我能够明确表示这是一个好的解决方案之前,我还有很长的路要走,而且我确信它并不是每个应用程序的最佳解决方案,但我相信这种组合会非常强大。我承认有一些缺点,例如失去了缓存资源的能力。但我有一种感觉,优势将超过它们。

我很想了解你在探索这种解决方案方面的进展情况。如果您有任何github实验,请指向它们。我目前没有,但希望很快就会有。

以下是我收集的待读链接列表。我不能保证它们都有价值,因为我只是浏览了其中许多内容。但希望其中一些可以帮到你。


使用Express和Socket.IO的绝佳教程。它将express会话公开给socket.io,并讨论如何为每个经过身份验证的用户设置不同的房间。


1
我刚回答了一个相关的问题,并加入了一些更多的想法:https://dev59.com/ZW445IYBdhLWcg3wdqEL#6829575 - Tauren
13
“在我能肯定地说这是一个好的解决方案之前,我还有很长的路要走。” - 只是好奇,这真的是一个好的解决方案吗?:D - inf3rno
9
请回复@Tauren。我非常想知道你现在有什么话要说。 - No_name
6
@Tauren,我也很好奇这个结果是怎样得出的? - Kurren
5
2020年了,我也很好奇 :-) - sw1337

65

HTTP、REST和WebSockets是非常不同的。HTTP是无状态的,所以Web服务器不需要知道任何信息,你可以在Web浏览器和代理中进行缓存。如果使用WebSockets,服务器将变得有状态,并且需要在服务器上与客户端建立连接。

请求-应答通信 vs 推送

只有在需要从服务器向客户端推送数据时才使用WebSockets,这种通信模式不包含在HTTP中(只有通过变通方法实现)。如果其他客户端创建事件需要对其他连接的客户端可用,例如在需要根据其他客户端行为采取行动的游戏中,或者如果你的网站正在监控某些内容并且服务器一直向客户端推送数据,例如股票市场(实时)。

如果不需要从服务器推送数据,通常更容易使用无状态的HTTP REST服务器。HTTP使用简单的请求-应答通信模式。


5
我们非常习惯单向模式,因为以前我们从来没有其他选择。但是现在随着我的应用程序变得更加完善,越来越明显的是,使用推送技术的地方越多,应用程序就会变得更加响应和有吸引力。 - Harry
我的应用程序显示了一个朋友列表,以及他们拥有的积分数量等信息。为什么不实时更新呢?如果用户能够看到他们的朋友在进步,那么他们可能更倾向于想要追赶上去。我有一些文档模型,虽然不是经常更改,但是稍微更改一下,不实时更新可能会导致轻微的混乱。在某些时候,你的网站从推送更新中受益匪浅,你开始审视你的代码,其中一半是关于REST,另一半是关于sockets,你说:“好吧,我想统一这个。” - Harry
4
可以考虑仅使用WebSockets向您的Web应用程序推送通知或命令(如带参数的getUpdate或refreshObjectWithId),这是一个选择。该命令可以在您的Web应用程序(客户端)中进行分析,并跟随REST请求以获取特定数据,而无需通过WebSockets传输数据本身。 - Beachwalker
2
Websockets比REST调用更容易的原因有很多,不仅仅是为了推送。http://www.websocket.org/quantum.html - B T
WebSockets非常棒,可以让服务器随时向客户端发送数据,而不仅仅是响应客户端消息。WebSockets实现了基于消息的协议,因此客户端可以随时接收消息,如果他们正在等待特定的消息,则可以将其他消息排队以供稍后处理,重新排序排队的消息,根据应用程序状态忽略推送的消息等等。我再也不会写基于REST的应用程序了。Flash也很容易使用,具有基于开源AS3的WebSocket实现和通过ExternalInterface(addCallback / call)方法回退到浏览器的功能。 - Triynko
Websockets 作为有状态的说法有些错误。您需要一个应用程序协议来使用它。并且您可以在其上轻松构建无状态协议。就像 HTTP 是建立在有状态 TCP 上的无状态协议一样。唯一的问题是您必须手动完成它。 - freakish

58
我正在考虑将所有网站功能转换为WebSocket api。
不,你不应该这样做。如果你支持两种模式,那么就没有害处。对于单向通信/简单请求,请使用REST;对于双向通信,特别是当服务器想要发送实时通知时,请使用WebSocket。
WebSocket比RESTful HTTP更高效,但在以下方面,RESTful HTTP仍然优于WebSocket。
  1. HTTP已经为创建/更新/删除资源定义了良好的操作。您需要在WebSockets的低级别实现这些操作。

  2. WebSocket连接在单个服务器上垂直扩展,而HTTP连接在水平方向上扩展。有一些专有的、非基于标准的WebSocket水平扩展解决方案。

  3. HTTP具有许多良好的功能,如缓存、路由、多路复用、压缩等。如果选择WebSocket,则必须在WebSocket之上构建这些功能。

  4. 搜索引擎优化对HTTP URL很有效。

  5. 所有代理、DNS和防火墙尚未完全了解WebSocket流量。它们允许端口80,但可能会先窥探流量并限制流量。

  6. WebSocket的安全性是全有或全无的方法。

请查看文章以获取更多详细信息。


3
这是最好的答案。 - MattWeiler
1
该主题的最佳答案 - Sanandrea
我的WebSocket连接可以通过CDN和负载均衡器。因此,我认为使用普通解决方案也可以水平扩展WebSockets。 - Aldian Fazrihady

14

使用TCP(WebSockets)作为主要的网站内容传递策略唯一的问题在于,关于如何使用TCP设计网站架构和基础设施的阅读材料非常少。

因此,你无法从别人的错误中学习,并且开发速度会变慢。这也不是一个“经过试验和测试”的策略。

当然,您也将失去HTTP的所有优势(无状态和缓存是最大的优势)。

请记住,HTTP是为提供网络内容而设计的TCP抽象。

还有,我们不能忘记SEO和搜索引擎不支持WebSockets。因此,您可以忘记SEO。

个人认为不应该使用WebSockets来提供网站,但如果您有小型玩具网站或个人网站,请尽管使用。尝试它,保持前沿。对于企业或公司而言,您无法证明使用WebSockets是值得冒险的。

不要使用WS用于提供网站,而是用于提供Web应用程序


13

我通过一些艰难的方式学到了一个小教训。我做了一个可以在 Ubuntu AWS EC2 云服务上运行的数字计算应用(使用强大的GPU),我想为它制作一个前端以便实时观看进度。

由于它需要实时数据,很明显我需要Websockets来推送更新。

这开始于一个概念验证,非常好用。但当我们想要向公众开放时,我们必须添加用户会话,所以我们需要登录功能。不管怎么看,WebSocket都必须知道它所处理的用户,因此我们采用了使用WebSockets来验证用户的捷径。这似乎是显而易见的且很方便。

我们实际上花费了相当多的时间来使连接变得可靠。我们从一些廉价的websocket教程开始,但发现我们的实现无法在连接断开时自动重新连接。当我们转向Socket-io后,一切都得到了改善。Socket-io 是必需品!

说了那么多,老实说,我认为我们错过了一些很棒的socket-io功能。Socket-io有很多更多的功能可以提供,如果您在初始设计中考虑到它,我相信您可以从中获得更多收益。相比之下,我们只是用socket-io的websocket功能替换了旧的websockets,就这样结束了。(没有房间、没有频道……)重新设计可能会使一切更强大。但我们没有时间做这件事。这是我们下一个项目需要记住的事情。

接下来,我们开始存储越来越多的数据(用户历史记录、发票、交易等)。我们将其全部存储在AWS DynamoDB数据库中,并再次使用socket-io将CRUD操作从前端传递到后端。我认为我们走错了方向。这是一个错误。

  • 因为不久之后,我们发现亚马逊的云服务(AWS)为RESTful应用程序提供了一些很棒的负载均衡/扩展工具。
  • 现在我们的印象是我们需要编写很多代码来执行CRUD操作的握手。
  • 最近我们实现了Paypal集成。我们设法让它工作。但是,所有教程都使用RESTful API来实现。我们不得不重写/重新思考他们的示例,以使用Websockets来实现。尽管我们很快就做到了,但感觉像是逆流而行。
  • 说了这么多,我们下周就要上线了。我们及时完成了一切工作,而且速度非常快,但是它能扩展吗?


    只是想知道,因为我们正在尝试自己做出这个决定,它在AWS上扩展得如何? - Gabe
    3
    @Gabe 显然,node可以轻松地在廉价的aws实例上处理数百个socket-io连接。我们还没有注意到性能问题。不过,有一个奇怪的影响,那些访问你网站但是在一个标签页中保持打开的人会继续使用连接。(在手机上经常发生这种情况)。因此,你需要至少一种机制来踢出空闲用户。目前我们还没有投入精力去做这件事,因为我们的性能并没有受到影响。因此,目前还没有必要进行扩展。 - bvdb
    1
    与此同时,我们正在将 Node.js 代码迁移到 NestJS,并在此过程中重写所有身份验证代码。我们将使用 REST 和 Websocket API 的混合。我们还将应用程序分成更小的微服务,而这正是 NestJS 在这方面为我们节省了很多工作量的地方。 - bvdb
    1
    四个月后,我们现在再次重写所有内容,使用AWS的Cognito和Amplify来为我们进行身份验证。 Amplify和Cognito对社交账户(Google、Facebook等)登录有很好的支持。 - bvdb
    1
    又有一个更新:与此同时,GraphQL正变得越来越流行,GraphQL还有一个名为“subscriptions”的功能。而且AWS现在有像AppSync这样支持GraphQL订阅的服务,甚至将来可以使它们与Lambdas一起工作。- 现在也要考虑这一点。 - bvdb

    5
    我会考虑同时使用两种技术。每种技术都有其优点,没有一种通用的解决方案。
    工作分离如下: 1. 当应用程序需要与服务器通信并需要会话时,WebSockets将是主要方法。这消除了许多旧浏览器所需的黑客攻击(问题在于旧浏览器的支持,这将消除此问题)。 2. RESTful API用于GET调用,这些调用不需要会话(即不需要身份验证),可以从浏览器缓存中受益。一个很好的例子是Web应用程序使用的下拉菜单的参考数据。但是,它可能比...更经常更改。 3. HTML和Javascript。 这些组成了webapp的用户界面。 通常将其放置在CDN上会更好。 4. 使用WSDL的Web服务仍然是企业级和跨企业通信的最佳方式,因为它提供了消息和数据传递的明确定义标准。主要您会将其卸载到Datapower设备以代理到您的Web服务处理程序。
    所有这些都发生在HTTP协议上,该协议已经通过SSL为我们提供了安全套接字。
    对于移动应用程序而言,WebSockets无法重新连接到已断开的会话(如何在关闭连接后重新连接到WebSocket),管理起来并不容易。因此,对于移动应用程序,我仍然建议使用REST API和轮询。
    在使用WebSockets与REST时需要注意的另一件事是可扩展性。WebSocket会话仍由服务器管理。当正确执行RESTful API时,它们是无状态的(这意味着没有需要管理的服务器状态),因此可扩展性可以水平增长(更便宜)而不是垂直增长。

    2

    我是否想从服务器接收更新?

    • 是: 使用Socket.io
    • 否: 使用REST

    使用Socket.io的缺点包括:

    • 可伸缩性: WebSockets需要打开连接,并需要一个非常不同的Ops设置以进行网页比例。
    • 学习: 我没有无限的时间学习。必须完成任务!

    我仍将在我的项目中使用Socket.io,但对于REST可以很好地解决的基本Web表单,不使用它。


    1

    WebSockets(或长轮询)基于传输主要用于服务器和客户端之间的(近乎)实时通信。虽然有许多情况需要这些类型的传输,例如聊天或某种实时提要或其他内容,但并不是某些 Web 应用程序的所有部分都必须与服务器双向连接。

    REST 是基于资源的架构,被广泛理解,并且相对于其他架构具有自己的优点。WebSockets 更倾向于实时数据流/提要,这将要求您创建一些基于服务器的逻辑,以便在资源和提要之间进行优先级或区分(如果您不想使用 REST)。

    我认为,随着这种传输方式越来越普及并以数据类型/表单不可知的交付形式更好地得到理解/记录,未来可能会出现更多 WebSockets 中心化框架,例如 socketstream。然而,我认为,这并不意味着它会/应该取代 REST,只因为它提供了在许多用例和场景中并非必需的功能。


    0

    我想指出这篇博客文章,在我看来,这是对这个问题最好的答案。

    简而言之,是的

    这篇文章包含了所有这种API的最佳实践。


    -2

    那不是一个好主意。标准甚至还没有最终确定,支持在各种浏览器中也不同等等。如果你现在想这样做,你最终会需要回退到Flash或长轮询等技术。未来它可能仍然没有太多意义,因为服务器必须支持保持连接对每个用户开放。大多数Web服务器的设计是为了快速响应请求并尽快关闭它们,而不是保持连接。甚至你的操作系统也必须调整以处理大量同时连接(每个连接使用更多的临时端口和内存)。尽可能使用REST来构建网站。


    是的,大多数Web服务器擅长处理HTTP协议。但Node.js不是一个Web服务器,而是一个I/O库。它同样也能很好地处理TCP协议。这个问题基本上是在问我们是否可以设计网站来使用TCP代替HTTP。 - Raynos
    同样的限制仍然存在,您仍然会耗尽临时端口/内存,它仍然会限制您可以同时服务多少人,并对系统造成不必要的负担。 - Zach Kelling
    是的,有一个限制,但如果您不为每个连接创建新线程,我认为这并不是什么大问题。 - Raynos
    我已经为每个用户准备了一个套接字。全局聊天+新闻订阅。 - Harry
    2
    我猜在2011年这是一个很好的答案。- 所以,我明白你的想法。但是在2019年,WebSockets已经成熟了。 - bvdb

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