0

当我加入房间,然后离开路线返回,然后使用我建立的聊天室时,我收到的消息数量是我离开和重新加入次数的两倍。

当我硬刷新时,这个问题就消失了。

到目前为止,我已经尝试了所有我能找到的东西,但一直无法让它工作。

我在客户端尝试过,beforeRouteLeavebeforeDestroywindow.onbeforeunload

  • this.$socket.removeListener("insertListener");--> 尝试了所有
  • this.$socket = null
  • this.$socket.connected = false
  • this.$socket.disconnected = true
  • this.$socket.removeAllListeners()
  • this.$socket.disconnect()

在相同的事件中,我还发送了一个this.$socket.emit("leaveChat", roomId),然后在服务器端在io.on("connection")接收器内部尝试了以下操作socket.on("leaveChat", function(roomId) {})

  • socket.leave(roomId)--> 根据文档,这是应该工作的;
  • socket.disconnect()
  • socket.off()- 似乎已被弃用
  • socket.removeAllListeners(roomId)

我尝试了很多其他的事情,我不记得了,但如果我这样做了,我会更新帖子。

要么它以某种方式断开连接,并且在重新加入时,以前的听众或某些东西仍然存在,这意味着所有消息都收到*次重新加入。或者,如果我断开连接,我似乎无法重新连接。

加入时,我向服务器发送房间 ID 并使用 socket.join(roomId)。

我想要做的就是不刷新,当我离开页面时,在此之前,用户可以离开房间,当他们返回时,他们可以重新加入,不会出现重复的消息。

我目前正在尝试仔细阅读源代码。

4

2 回答 2

1

在这里全面披露,我没有阅读 roberfoenix 提出的完整回复,但这是 socket.io 的一个常见问题,它归结为多次调用“on”事件。

当您为套接字创建 .on 事件时,它是一个绑定,您可以多次绑定到同一个事件。

我的假设是,当用户点击页面时,您会运行类似

socket.on("joinRoom", 数据)

这反过来会说加入房间,从 Mongo(或其他东西)中提取您的消息,然后发送到房间(旁注,使用 .once on 可以帮助您在用户加入房间时不会向每个用户发送)

现在你离开房间,调用 socket.emit('leaveRoom',room),冷静下来,你离开房间,然后你回到房间,猜猜你现在刚刚再次绑定到同一个 on 事件,所以当你发射时,它向该用户等发出两次等。

我们解决这个问题的方法是将我们所有的 on-events 放入一个函数中并调用该函数一次。因此,用户加入一个页面,这将运行 socketInit() 之类的函数;

socketInit 函数会有这样的东西

function socketInit(){
if (init === false){
//Cool it has not run, we will bind our on events
socket.on("event")
socket.on("otherEvent")

init = true;
}


}

基本上 init 是一个全局变量,如果为 false,则绑定你的事件,否则不要重新绑定。

这可以通过使用 Promis 进行改进,或者可以在连接时完成,但如果用户重新连接,它可能会再次运行。

于 2020-10-14T23:22:56.193 回答
0

如果您正在使用 Vue-Socket 并且尝试了所有方法后感觉有点发疯,这可能是您的解决方案。

事实证明,具有挑战性的核心假设和从头开始的调查是有回报的。可能你在 Socket.io 中忘记了自己太深,以至于忘记了你在使用 Vue-Socket。

我的解决方案是使用 Vue-Socket 内置的取消订阅功能。

使用 Vue-Socket,您最初可以订阅事件的一种方式如下:

this.sockets.subscribe('EVENT_NAME', (data) => {
    this.msg = data.message;
}); 

因为您使用的是 Vue Socket,而不是常规的,所以您还需要在离开房间之前使用Vue Socket 的方式取消订阅(除非您正在寻找一个非常定制的解决方案)。这就是为什么我怀疑我尝试过的许多其他事情都不起作用并且几乎什么也没做!

你这样做的方式如下:

this.sockets.unsubscribe('EVENT_NAME');

对任何以重复形式给您造成麻烦的事件执行此操作。首先你会得到重复的原因,特别是在离开房间后重新加入时,是因为以前的事件监听器仍在运行,现在单个用户将扮演两个或多个监听器的角色。

另一种可能性是您将消息发送给所有人,包括原始发件人,而您很可能应该将其发送给除发件人以外的其他所有人(请在此处查看 socket.io emit cheatsheet)。

如果上述方法不能为您解决问题,请确保您实际上是在离开房间,并在服务器端这样做。您可以通过在离开路由之前向服务器发出信号(如果您使用的是反应式单页应用程序)、在服务器端接收它并socket.leave(yourRoomName)在您的io.on("connection", function(socket) {})实例中调用 ' ' 来实现这一点。

于 2020-10-14T17:21:11.437 回答