You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js+Express+Socket.io:如何检测用户清除Cookie或会话超时?

解决Socket.io无法检测会话超时/Cookie清除的问题

刚好我之前也碰到过一模一样的场景——Express会话过期或者用户清了Cookie,但Socket连接还连着,导致在线状态和通知都出问题。咱们可以从绑定会话与Socket连接、服务器端主动检测、客户端主动校验这几个方向来解决,下面给你具体的思路和代码:

1. 先把Socket连接和Express会话绑定起来

Socket.io和Express的会话默认是独立的,所以第一步要让它们关联上,这样我们才能通过会话状态判断用户是否有效。

假设你用的是express-session,可以这样整合:

const express = require('express');
const session = require('express-session');
const http = require('http');
const { Server } = require('socket.io');

const app = express();
const server = http.createServer(app);

// 配置Express Session
const sessionMiddleware = session({
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: false,
  cookie: { maxAge: 3600000 } // 1小时超时示例
});

// 把Session中间件挂载到Express
app.use(sessionMiddleware);

// 让Socket.io使用这个Session中间件
const io = new Server(server);
io.use((socket, next) => {
  sessionMiddleware(socket.request, socket.request.res, next);
});

// 用一个Map来存储SessionID和Socket实例的映射
const sessionSocketMap = new Map();

io.on('connection', (socket) => {
  const sessionId = socket.request.session.id;
  
  // 绑定Session和Socket
  sessionSocketMap.set(sessionId, socket);
  console.log(`User connected, session ID: ${sessionId}`);

  // 断开时移除映射
  socket.on('disconnect', () => {
    sessionSocketMap.delete(sessionId);
    console.log('User disconnected');
  });
});

2. 服务器端主动检测会话超时

现在会话和Socket绑定了,我们可以定时检查会话是否过期,一旦过期就主动断开Socket:

// 每隔30秒检查一次所有活跃的Socket对应的会话
setInterval(() => {
  for (const [sessionId, socket] of sessionSocketMap.entries()) {
    const currentSession = socket.request.session;
    // 检查会话是否存在,或者是否已过期
    if (!currentSession || Date.now() > currentSession.cookie.expires.getTime()) {
      // 强制断开Socket
      socket.disconnect(true);
      sessionSocketMap.delete(sessionId);
      console.log(`Session expired for ${sessionId}, disconnected socket`);
    }
  }
}, 30000);

如果你的Session是存在Redis里的(生产环境推荐),还可以订阅Redis的键过期事件,一旦会话对应的键过期,直接找到对应的Socket断开,这样更高效。

3. 客户端主动检测Cookie状态

用户手动清除Cookie的时候,服务器端没法立刻知道,所以客户端可以定时检查登录相关的Cookie是否存在,不存在就主动断开Socket:

<script src="/socket.io/socket.io.js"></script>
<script>
  const socket = io();

  // 每隔10秒检查一次Session Cookie(默认是connect.sid)
  setInterval(() => {
    const hasSessionCookie = document.cookie.includes('connect.sid');
    if (!hasSessionCookie && socket.connected) {
      socket.disconnect();
      console.log('Cookie cleared, disconnected socket');
      // 这里还可以跳转到登录页之类的
    }
  }, 10000);
</script>

4. 增强Socket.io的Ping/Pong验证

Socket.io本身有心跳机制,我们可以在服务器端的Ping事件里加一层会话校验,确保每次心跳都验证用户的会话有效性:

io.on('connection', (socket) => {
  // 监听客户端的Ping请求
  socket.on('ping', () => {
    const currentSession = socket.request.session;
    if (!currentSession || Date.now() > currentSession.cookie.expires.getTime()) {
      // 会话无效,直接断开
      socket.disconnect(true);
    } else {
      // 会话有效,返回Pong
      socket.emit('pong');
    }
  });
});

总结

把这几个方法结合起来,就能实现类似窗口关闭时的disconnect事件效果:

  • 绑定会话和Socket,让两者状态关联
  • 服务器定时检查会话,过期就断开Socket
  • 客户端主动检测Cookie,清除后主动断开
  • 利用心跳机制实时验证会话有效性

这样就能解决用户清Cookie或会话超时后,Socket还连着的问题,好友列表的在线状态也能同步更新了。

内容的提问来源于stack exchange,提问作者andrew1515

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:24:13