在重新连接、socket.io、node.js 时重用套接字 id
Posted
技术标签:
【中文标题】在重新连接、socket.io、node.js 时重用套接字 id【英文标题】:reuse socket id on reconnect, socket.io, node.js 【发布时间】:2013-08-20 02:49:30 【问题描述】:是否可以重复使用 socket.id 或多次使用它?
假设用户在不同的浏览器选项卡中查看同一站点的多个页面。我想用一个socket.id,socket来处理它们。
如果用户收到通知,它应该在所有选项卡上弹出一个 socket.emit。
【问题讨论】:
【参考方案1】:有可能
从以前的回复日期来看,我认为在以前的 socket.io 版本中可能不可能,但我可以确认我在重新连接 socket.io 2.3.0 时成功地重用了套接字 ID。
您只需要覆盖io.engine.generateId
。无论该方法返回什么,都将是分配给套接字的 id。这是docs about generateId。
就我自己的实验而言,调用该方法有两种情况。在连接和重新连接期间。
io.engine.generateId
方法接收原始请求对象作为参数,因此我们可以使用它来确定是要重用 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
生成的哈希匹配。
【讨论】:
感谢您的详尽回答! 我的情况是我没有手动重新连接,浏览器端的socket.io在连接丢失时会自行重新连接,可以让它回到同一个socket.io id吗? @datdinhquoc 我认为在这种情况下它会自动重新使用 id。无论如何,您可以通过实现第 1 点和第 3 点手动强制它重用它。您需要在客户端上保存给定的 socketId 才能在第 3 点发送它。我建议使用类似 sessionStorage 的方法跨度> @Daniel Reina ,我正在尝试效仿您的示例并覆盖 generateId()。但它不起作用,因为 searchparams 之后的代码由于某种原因永远无法到达。我在前后插入了一个日志语句。第二个不打印。同样在前端,我收到 400 bad request 作为错误。 @Atr0x 我会尝试返回一个硬编码的字符串。如果可行,我会查看io.engine.generateId
收到的req
参数。听起来您没有收到您期望收到的参数。【参考方案2】:
您不能重复使用 Socket.IO 连接 ID,因为它们是在客户端-服务器握手期间创建的,但还有其他方法。我没有任何示例,但是您可以修改 Socket.IO 客户端以在执行握手时传递查询字符串。然后你可以告诉服务器根据查询字符串来处理客户端,然后用某个查询字符串获取所有客户端ID。
您可以使用的另一种方法是使用命名空间。假设您有某种类型的会话系统,您可以创建一个特定于会话的命名空间,并将具有该会话 ID 的客户端直接连接到该命名空间。
【讨论】:
房间和命名空间有什么区别?【参考方案3】:多个网站?
不,这是不可能的。我猜,如果您将这些网站打开到您的 web 应用程序中的 iframe 中,那将是可能的。
另一种选择是构建一个打开套接字连接的浏览器插件。
【讨论】:
我想我会使用命名空间。谢谢。 好吧,您说的是多个站点。网站不是页面。下次更具体;)以上是关于在重新连接、socket.io、node.js 时重用套接字 id的主要内容,如果未能解决你的问题,请参考以下文章
Phaser.js 中的 Node.js 和 Socket.io 未连接 socket.io/?EIO=3&transport=polling