让socket.io客户端版本落后于服务器版本

时间:2015-04-14 02:05:05

标签: sockets go websocket socket.io

场合

我们正在使用socket.io进行移动服务器通信。由于我们无法强制升级用户的设备,如果我们想升级到版本1(非反向兼容),我们必须在服务器上处理这两个版本一段时间。

问题

有哪些选择?

我目前最喜欢的是将旧版本和新版本包装在多路复用器中。它根据头和查询参数检测传入请求的版本,从而知道要调用哪些函数。

另一个(shittier)选项是将新版本包装在一个模块中,该模块可以在必要时将旧版本的协议转换为新版本(并再次返回)。这具有严重的缺点。确保我已经正确地确定并处理了所有微小的差异,这将是一项耗时且不确定的工作。一些差异可能需要一些严重的按摩。

(如果您感到好奇或知道有帮助,我们会在Go中这样做。)

3 个答案:

答案 0 :(得分:2)

您似乎可以在服务器上运行两个单独版本的socket.io.由于这两个版本没有唯一的模块文件名,因此您可能需要从不同的路径加载一个版本。然后,显然在加载模块并初始化它们时,您将它们分配给不同命名的变量。例如:

var io_old = require('old/socket.io');
var io = require('socket.io);

一旦你在服务器上加载了两个版本,我认为有两种不同的方法可以运行它们。

1)为每个版本使用不同的端口。旧版本将使用与node.js Web服务器共享的默认端口80(无需更改配置)。较新的版本将在不同的端口(例如端口3000)上运行。然后,您将每个版本的socket.io初始化为其自己的端口。然后,您的新版本客户端将连接到运行较新版本的端口。

对于在端口80上运行的旧socket.io服务器,您将使用您已经拥有的任何可能挂钩到现有http服务器的初始化。

对于在其他端口上运行的新socket.io服务器,您可以单独初始化它:

var io_old = require('old/socket.io')(server);
var io = require('socket.io')(3000);

然后,在新版本客户端中,您将在连接时指定端口3000。

var socket = io("http://yourdomain.com:3000");

2)为每个版本使用不同的HTTP请求路径。默认情况下,每个socket.io连接都以一个如下所示的HTTP请求开始:http://yourdomain.com/socket.io?EIO=xx&transport=xxx?t=xxx。但是,该请求的/socket.io部分是可配置的,并且socket.io的两个单独版本可以各自使用不同的路径名。在服务器上,启动socket.io侦听的.listen()方法采用可选的选项对象,可以使用path: "/socket.io-v2"中的自定义路径进行配置。同样,客户端中的.connect()方法也接受该选项对象。这个选项很难找到the documentation,因为它实际上是一个engine.io选项(socket.io使用),但是socket.io将选项传递给engine.io。

我自己没有尝试过这些,但我研究了如何从客户端和服务器启动socket.io连接,看起来底层引擎支持这种功能,我看不出它为什么不能工作的原因。

以下是您如何更改服务器上的路径:

var io = require('socket.io')(server, {path: "/socket.io.v1"});

然后,在新版本的客户端代码中,您将连接如下:

var socket = io({path: "/socket.io.v1"});

这将导致初始连接请求发送到HTTP URL,如下所示:

http://yourdomain.com/socket.io.v1?EIO=xx&transport=xxx?t=xxx

这将由HTTP服务器上的不同请求处理程序处理,从而将两个版本分开。


仅供参考,socket.io连接URL中的EIO=3查询参数实际上也可能是engine.io版本号,也可用于识别客户端版本和“做正确的事”基于该值。我还没有找到任何关于它如何工作的文档,甚至无法找到在engine.io或socket.io源代码中查看查询参数的位置,因此需要进行更多调查作为另一种可能性。

答案 1 :(得分:0)

我真的没有立即解决这个问题,但我有一些建议。我猜你可以用它来节省很多时间。

  • 首先,我在一个使用socketIo的初创公司工作 一切
  • 我们知道这个问题会发生,所以我们最初的设计是为了 使所有东西都可以插入,这意味着我们可以换掉socketio sockjs,它仍然有效。
  • 它的完成方式是定义很少改变的通用API集 在一个系统中。我们称之为经理。管理人员可以公开其他开发人员需要使用的API,而不会弄乱任何东西。它加速了很多。
  • 管理器实现在后台更改,但API仍然相同,因此在核心上工作的工程师可以自信地进行更改。
  • 好像你对代码有很强的依赖性。或者可能不是。我不确定。如果你没有,请尝试遵循这个原则。

答案 2 :(得分:0)

我们将把0.9.x版本和当前版本保持为服务器上的独立库。最终,当客户端池或多或少全部更新时,我们只需拔掉0.9.x版本的插件。

我们管理这两个版本的方法是将socket.io服务包装在一个包中,该包将确定将请求传递给哪个包装的s​​ocket.io版本。此确定将取决于请求的功能,例如自定义标头(可以添加到较新的客户端)以及查询参数和由一个版本或另一个版本专用的其他标头。

由于我们使用Go,到目前为止还没有普遍认同的方法来管理依赖关系,更不用说一种可以尊重版本差异的方法。假设回购的back-compat分支没有被破坏(它是),我们有两个选择。第一个是fork repo并使back-compat版本成为master。然后我们将其导入,就好像它与另一个无关。第二种选择是使用gopkg.in假装单独的分支是单独的回购。

在任何一种情况下,我们都可以像这样导入两个分支/回购

import (
    socketioV0 "github.com/path/to/older/version"
    socketioV1 "github.com/path/to/current/version"
)

然后使用导入名称socketioV0socketioV1在代码中引用它们。