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

ifsvaxew  于 2023-01-25  发布在  Node.js
关注(0)|答案(3)|浏览(146)

是否可以重用socket.id或多次使用www.example.com?
假设用户在不同的浏览器选项卡中查看同一站点的多个页面,我想使用一socket.id来处理所有这些页面。
如果用户收到通知,则应在所有选项卡上弹出一个socket.emit。

ni65a41a

ni65a41a1#

∮有可能∮
从以前的回复日期来看,我认为这在以前版本的www.example.com中可能是不可能的,但我可以确认,我在与socket.io2.3.0重新连接时成功地重用了套接字ID。socket.io, but I can confirm that I'm successfully reusing socket ids on reconnections with socket.io 2.3.0.
你只需要重写io.engine.generateId。无论那个方法返回什么,都将是分配给套接字的id。下面是关于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生成一个新的套接字id。特别使用那个库的原因是因为那是原始方法所做的。在这里你可以找到源代码。

2.发送连接请求信息

一旦你有了它,你需要从客户端发送socketId参数,这在文档中有描述。

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

process.env.WEBSOCKET_URL将是Web套接字侦听的URL。
请注意,这在连接时有效,但您可能希望在重新连接时更新查询。

3.发送关于重新连接请求的信息

在文档的同一部分,它解释了如何在重新连接之前更新查询参数。你只需要做一些类似的事情。

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生成的散列匹配。

xjreopfe

xjreopfe2#

您不能重用Socket.IO连接ID,因为它们是在客户端-服务器握手期间创建的,但是有替代方法。我没有任何示例,但是您可以修改Socket.IO客户端,使其在执行握手时沿着查询字符串。然后您可以告诉服务器根据查询字符串处理客户端,并在以后使用某个查询字符串获取所有客户端ID。
另一种方法是使用名称空间,假设你有某种类型的会话系统,你可以创建一个特定于会话的名称空间,并将客户端与该会话ID直接连接到该名称空间。

at0kjp5o

at0kjp5o3#

多个站点?
不,这是不可能的。我想,如果你在你的网络应用程序中将这些网站打开到iframe中,那就有可能了。
另一种选择是构建一个浏览器插件来打开套接字连接。

相关问题