在重新连接,socket.io,node.js上重用套接字ID

时间:2013-08-18 00:32:17

标签: node.js socket.io

是否可以重复使用socket.id或多次使用它?

假设用户在不同的浏览器标签中查看同一网站的多个页面。我想使用一个socket.id,socket来处理它们。

如果用户收到通知,则应在所有选项卡上弹出一个socket.emit。

3 个答案:

答案 0 :(得分:6)

可能

从以前的答复开始,我认为在先前版本的socket.io中可能无法实现,但是我可以确认在与socket.io 2.3.0进行重新连接时,我已成功重用了套接字ID。

您只需要覆盖io.engine.generateId。该方法返回的值将是分配给套接字的ID。这是docs about generateId

就我自己做过的实验而言,调用该方法有两种情况。在连接和重新连接期间。

方法io.engine.generateId接收原始请求对象作为参数,因此我们可以使用它来确定是要重用ID还是获得新的ID。

示例

作为示例,我将展示如何重用从客户端发送的ID,或者在客户端不发送ID时创建一个新ID。 ID将在握手请求中作为查询参数socketId发送。

1。覆盖io.engine.generateId

首先,您需要覆盖io.engine.generateId,这是分配ID的方法。在服务器上,您需要执行以下操作。

const url = require('url')
const base64id = require('base64id')

io.engine.generateId = req => {
  const parsedUrl = new url.parse(req.url)
  const prevId = parsedUrl.searchParams.get('socketId')
  // prevId is either a valid id or an empty string
  if (prevId) {
    return prevId
  }
  return base64id.generateId()
}

这样,每当您在握手请求中发送查询参数socketId时,它将被设置为套接字ID。如果不发送,则将使用base64id生成一个新的。特别使用该库的原因是因为这就是原始方法所做的。在这里您可以找到source code

2。发送有关连接请求的信息

一旦有了,就需要从客户端发送socketId参数。这在the docs中有描述。

const socket = io.connect(process.env.WEBSOCKET_URL, {
  query: {
    socketId: existingSocketId || ''
  }
})

process.env.WEBSOCKET_URL是您的Web套接字正在监听的URL。

请注意,这在连接时将起作用,但是您可能希望在重新连接时更新查询。

3。发送有关重新连接请求的信息

the docs的同一部分中,说明了在重新连接之前如何更新查询参数。您只需要做这样的事情。

socket.on('reconnect_attempt', () => {
  socket.io.opts.query = {
    socketId: existingSocketId || ''
  }
});

就像那样,只要您从客户端发送相同的套接字ID,您就将重新使用它。

安全问题

信任从客户端发送的信息来分配套接字ID可能不是一个好主意。我建议发送加密签名的有效负载,将该有效负载存储在客户端中,并在连接和重新连接时将其发送回服务器。这样,服务器可以通过验证签名来检查是否可以信任有效载荷。

使用上面的相同示例,我们会将类似的内容发送给客户端,也许是.on('connect')

{
  socketId: 'foo',
  signature: SHA_256('foo' + VERY_SECRET_PASSWORD)
}

客户端将存储该有效负载,并在连接或重新连接时将其发送回,就像我们之前发送socketId一样。

服务器收到签名的有效负载后,可以在io.engine.generateId内检查有效负载中的签名是否与使用ID和VERY_SECRET_PASSWORD生成的哈希值匹配。

答案 1 :(得分:2)

您不能重复使用Socket.IO连接ID,因为它们是在客户端 - 服务器握手期间创建的,但还有其他方法。我没有任何示例,但您可以修改Socket.IO客户端以在执行握手时传递查询字符串。然后,您可以告诉服务器根据查询字符串处理客户端,然后使用特定查询字符串获取所有客户端ID。

您可以使用的另一种方法是使用命名空间。假设您有某种类型的会话系统,您可以创建一个特定于会话的命名空间,并将具有该会话ID的客户端直接连接到该命名空间。

答案 2 :(得分:-1)

多个网站?

不,那是不可能的。如果您在webapp中将这些网站打开为iframe,我猜是可能的。

另一种选择是构建一个打开套接字连接的浏览器插件。