在“连接”上使用 socket.io 服务器持久化数据

Posted

技术标签:

【中文标题】在“连接”上使用 socket.io 服务器持久化数据【英文标题】:Persisting data with socket.io server on 'connect' 【发布时间】:2017-01-14 07:55:28 【问题描述】:

我将 socket.io 与 MongoDB 和 Promise 一起使用。我想在建立会话时在 Mongo 中保存一些数据,并且在保存这些数据之前不一定能正确处理进一步的套接字事件。

// Simplified code
io.sockets.on('connection', function(socket) 
  var req = socket.handshake;

  mongoDbPromise.then(function (db) 
    return db.collection('mycollection').insert(some_user_data: req.query.some_user_data);
  ).then(function (insertResult) 
    // do some other work
  ).catch(function (error) 
    socket.disconnect();
    logger.info(error);
  );

我遇到的问题是 connection 套接字事件在此连接处理程序返回后立即发出,但是当 MongoDB 的承诺解决并且我的 then 处理程序被调用时,设置连接的工作仍在继续。在收到connection 后立即发出请求的客户端会看到应用处于不一致状态。

我可以看到两种方法来解决这个问题:

1) 使用某种回调来控制何时发出connection。不过,我在 socket.io 文档中没有看到任何迹象表明可以这样做。

2) 不要使用connection 来表示套接字已准备就绪,而是使用其他一些自定义事件(我们称之为connection_established)并在then 处理程序中发出它。

选项 1 可能吗?有没有更好的方法来处理这种情况?

【问题讨论】:

几周前,我实现了this article 中描述的方法,对我来说效果很好。基本上,您允许客户端成功连接,但在完成身份验证/数据查找后,有第二个商定的握手消息。基本上是您的选择 2)。 【参考方案1】:

好吧,如果您在连接处理程序中要做异步工作(您这样做),那么在您完成连接处理程序中的工作之前,您不能阻止客户端认为它已连接。你有几个选择来解决这个问题:

    您可以使用中间件挂钩到 socket.io 连接的身份验证过程,并使用该功能来控制事物。如果您的数据库操作失败,您实际上会表现得好像连接未授权,这将断开连接。

    您可以将您自己的“connectionReady”消息发送给客户端,并设置客户端在收到“connectionReady”消息之前不向您发送任何内容,您只会在连接完成后发送该消息事情(听起来你已经有了这个想法,想到了 connection_established)。

socket.io v1 及更高版本中的身份验证过程可以使用这样的中间件完成:

io.use(function(socket, next) 
  var req = socket.handshake;

  mongoDbPromise.then(function (db) 
    return db.collection('mycollection').insert(some_user_data: req.query.some_user_data);
  ).then(function (insertResult) 
    // do some other work

    // socket is now ready to go
    next();
  ).catch(function (error) 
    // error on authentication
    next(new Error('not authorized');
    logger.info(error);
  );
);

connectionReady 进程可以这样工作:

// Simplified code
io.sockets.on('connection', function(socket) 
  var req = socket.handshake;

  mongoDbPromise.then(function (db) 
    return db.collection('mycollection').insert(some_user_data: req.query.some_user_data);
  ).then(function (insertResult) 
    // do some other work

    // send client a message indicating that the connection is now ready
    socket.emit("connectionReady", true);
  ).catch(function (error) 
    socket.disconnect();
    logger.info(error);
  );

【讨论】:

@Pathogen - 这回答了你的问题吗? 几乎!我忽略了一个细节:我现在坚持使用 socket.io 0.9x。 next 回调正是我希望在授权者中使用的,但我坚持使用旧风格的 io.set('authorization', ... ) API 进行授权。除非0.9x可以使用中间件进行授权? @Pathogen - 是的,0.9x 与 1.0+ 有很大不同。如果您寻求帮助,您将始终不得不提及,因为几乎没有任何 0.9x 开发,甚至更少的文档。如果这对您有所帮助,请向社区表明这一点,然后单击答案左侧的绿色复选标记。这也将为您在堆栈溢出时获得一些声誉积分,以遵循正确的程序。

以上是关于在“连接”上使用 socket.io 服务器持久化数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 android 上检查 socket.io 连接或断开连接?

来自互联网的本地 Socket.io 连接

带有 iOS 的 Socket.io 未在移动客户端上连接

android studio连接io.socket:sokect.io-client服务器的条件

Socket.IO 和 HapiJS 之间的连接

在 Socket.io 中使用第一个连接发送一些状态