SockJS - Web 消息并非易事
使用 Web 浏览器实现“实时 Web”或消息传递的想法已经存在相当一段时间了。最初被称为“长轮询”,然后是“Comet”,最新的版本称为“WebSockets”。毫无疑问,这是一个好的方向,WebSockets 是一项不错的技术。
但在争夺实时功能的过程中,我们忽略了真正重要的事情——如何实际使用消息传递。在 Web 上下文中,所有内容都是请求-响应驱动的,将典型的 Web 架构与异步消息传递结合起来并非易事。
现状
曾有多次尝试创建通用的组件,该组件可以加入 Web 架构并以类似于数据库处理数据的方式处理“消息传递”。
不过,存在一个问题,消息传递的异步特性和浏览器跨域限制意味着,为了使“Comet”工作,需要使用特定的 Web 架构。这是一个典型的供应商锁定案例。
新方法
至少过去是这样。您可以拥有一个 Web 消息传递框架,但您基本上与之绑定。
直到不久前,Socket.io 项目出现了。它构建在 Node.js 之上,这使其处于独特的位置,不仅 Node.js 中的所有内容都已经是完全异步的(几乎不可能搞砸),而且它还使用了 Web 环境中已使用的通用语言。
早期的 Socket.io 开发专注于消息传递,换句话说,如何将消息传递到 Web 浏览器和从 Web 浏览器获取消息。与 Web 开发人员的约定很简单:这是一个异步传输层,您可以在其之上使用 JavaScript 构建您的应用程序逻辑。
开发人员需要编写一个薄薄的 JavaScript 层,将 Socket.io 连接与应用程序连接起来,实现细节留给开发人员。应用程序可以使用 Node 或任何其他架构。它可以使用几乎任何方法连接,例如 Redis、RabbitMQ 或 HTTP 回调。
但最近 Socket.io 改变了重点,它不再只是一个简单的传输层,它开始成为一个完整的消息传递栈,其功能包括:
- 消息确认
- 广播 / “房间”
- 多路复用
- 易失性消息
没有银弹
但这里有一个问题:如果您构建消息传递语义,消息传递库将开始成为一个框架,并很快与平台绑定。
想想看,即使您尝试构建一个简单的“广播”抽象,也难免需要回答许多不明显的问题:
- 应用程序将如何部署?(限制在一个服务器上还是使用底层消息总线进行扩展?什么消息总线?它如何与 HTTP 负载均衡器配合使用?)
- 谁被授权“订阅”该广播数据?是公开的?如何设置权限?
- 谁可以发布消息?订阅者如何可靠地识别消息的作者?
请记住,“广播”是一个非常简单的抽象,在实践中,每个人都以不同的方式使用消息传递,并且很难创建通用的消息传递框架。消息传递框架做出的许多决策实际上都是特定于应用程序的。
- 授权(谁可以听到什么以及在哪里发布)
- 数据理解(如何执行值 + 更新?差异算法是什么?)
- 存在(所有应用程序都需要对此略有不同的含义)
我很高兴 Socket.io 的开发进展顺利,并且我仍然对它抱有希望。但在我看来,它关注的是错误的问题:我不需要另一个与特定平台绑定的有主见的、限定的消息传递框架。
相反,我只需要一个稳定的传输层。
后续步骤
Socket.io 指明了方向——有一个空间可以容纳一个简单而稳定的库,该库可以解决消息传递问题,并在本机实现广泛部署之前启用类似 WebSockets 的 API。所有这些都不需要定义消息传递模型,请注意。
这是我的回复:SockJS - 一个具有类似 WebSockets 的 API 的库,仅专注于传输层。虽然项目还很年轻,但我认为它已经比其他类似的库更胜一筹了。
该项目分为两部分:
- 浏览器 JavaScript 库:SockJS-client
- Node 的服务器端组件:SockJS-node
如果您想查看它的运行情况,以下是一些托管 QUnit 测试的实时部署:
- https://sockjs.popcnt.org/(托管在欧洲)
- https://sockjs.cloudfoundry.com/(CloudFoundry,WebSockets 已禁用)
- https://sockjs.cloudfoundry.com/(CloudFoundry SSL,WebSockets 已禁用)
- https://sockjs.herokuapp.com/(Heroku,WebSockets 已禁用)
SockJS 背后的主要假设是:
- API 应尽可能地模仿 WebSocket API。
- 服务器端部分应该很简单,所有复杂性都应该由浏览器库处理。(假设只有一个浏览器库,并且将会有许多服务器端实现。我们有一个 SockJS Node 服务器,并且我们希望至少创建一个 Erlang 服务器。)
- 内部不使用 Flash,仅使用 JavaScript。
- 回退到缓慢且愚蠢的轮询传输,当客户端位于公司防火墙和代理后面时很有用。
- 所有传输都必须是跨域的 - 开发人员必须能够将 SockJS 服务器作为其基础架构的单独部分托管。
- 支持常见的负载均衡策略:使用基于 JSESSIONID cookie 的粘性会话或基于前缀的均衡。
未来
解决消息传递问题仅仅是第一步。最终目标是为 Web 应用程序创建一个通用的消息传递框架,但这并非易事。这需要大量的工作和许多失败的尝试。因此,拥有一个稳定、设计良好、可重用的传输层非常重要。
(文章也可在 github 页面 上获取)