在Socket.IO中保存Socket数据

10
我希望在服务器端的socket上保存一些数据,这样当客户端向服务器发射任何数据时,就可以使用该数据!
一个应用场景是在socket上存储一个token。当客户端第一次连接时,它会发出token(如果有的话),否则会显示登录页面,然后将登录数据发送到服务器。无论哪种情况,我都想在服务器上存储token,以便之后的每个请求不需要指定token。
稍后,我将使用RedisStore,因此所有数据都将在运行应用程序的所有服务器上访问。
我的唯一问题是,在哪里存储与该客户端相关联的数据?
3个回答

11

http://socket.io/#how-to-use页面中,滚动至“存储与客户端相关的数据”一节

使用 socket.set 和 socket.get 实现异步设置和获取数据


3
那种方法在socket.io 1.0上似乎不再起作用了,有可能更新吗? - dievardump
1
io.set() 和 io.get() 方法在 1.0 版本中已被弃用。您需要使用中间件。http://socket.io/docs/migrating-from-0-9/ - Pierre Maoui
此链接已过期。 - Beki

0

我也遇到了同样的问题,猜测在socket.io 4.x版本中示例代码发生了什么。

在这个示例中,他们使用中间件use函数注册中间件)。

namespace.use((socket, next) => {
  // get data from client
  const sessionID = socket.handshake.auth.sessionID;
  const {userId, username} = yourFunction();
  // set socket specific data
  socket.sessionID = sessionID;
  socket.userID = session.userID;
  socket.username = session.username;
  next();
});

当套接字连接到服务器时,中间件将被执行。

然后,您可以使用数据。

注意- Socket.IO参考告诉我们使用socket.data以此为目的。

namespace.on('connection', socket => {
    socket.emit("join", `${socket.username} has been joined`);
})

如果您使用多个服务器,则必须牢记数据仅适用于该服务器。

在多服务器环境中,您需要一个单一的数据源,该数据源将由套接字服务器使用。

namespace.use(async (socket: Socket & { sessionID?: string, userID?: string, username?: string }, next) => {
    const sessionID = socket.handshake.auth.sessionID; // [socket.handshake][4]
// or other [socket related attributes][4]
    if (sessionID) {
        // you have to implement a function to save and retrive session info
        const session = await someFunctionToRetrieveSession(sessionID);
        if (session) {
            socket.sessionID = sessionID;
            socket.userID = session.userID;
            socket.username = session.username;
            return next();
        }
    }
    const username = socket.handshake.auth.username;
    if (!username) {
        return next(new Error("invalid username"));
    }
    socket.sessionID = randomId();
    socket.userID = randomId();
    socket.username = username;
    next();
});

还有一件事,据我所理解,当命名空间使用函数仅适用于命名空间时,如果您的客户端使用的是不同于默认值的其他命名空间,则默认('/')使用函数将不会被调用。

//client side
io("/chat");
...

//server side
io.use() // == io.of('/').use() will not be called
io.of('/chat').use() // only will be called

感谢示例的作者使用redis实现了sessionStorage,请参考this example code

有了这个信息,我猜测socket.io服务器会将socket的信息保存在内存中,并设置一个属性来保存socket及其相关数据。当socket再次连接时,服务器会检索socket及其相关数据。但由于这发生在内存中,所以无法在其他服务器之间共享信息,因此您必须找到一种与其他服务器共享数据的方法(例如redis)。


-1

当您不想使用任何数据库时,可以将数据保存在全局变量上。

var globalVariable = {};

io.sockets.on("connection", function (socket) {

    socket.on("save-client-data", function (clientData) {
          var clientId = clientData.clientId;
          globalVariable[clientId] = JSON.parse(clientHandshakeData);
    });

    socket.on("get-client-data", function (clientId) {

          var clientData =  globalVariable[clientId];
          socket.emit("get-client-data", JSON.stringify(clientData));

    });

});

这对我的情况起作用了,但我不知道性能影响。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接