为什么socket.io结合express-session使用时中间件不执行next函数
问题根因
- 你定义的
session是无参数工厂函数,调用后才会返回符合(req, res, next)格式的express-session中间件实例。你在io.use中直接给session传入socket.request、空对象和next三个参数,这些参数会被完全忽略,仅返回了新的中间件实例但没有执行,所以next永远不会被调用,握手流程卡住。 - 手动调用
next会跳过session中间件的异步执行流程,session还没挂载到request对象上就进入连接逻辑,自然返回undefined。 - 额外代码错误:
disconnect事件需要在单个socket连接实例上监听,绑定在io实例上不会触发。
修正方案
1. 复用同一个session中间件实例
不要用工厂函数重复创建session实例,直接创建一次全局复用:
const day = 1000 * 60 * 60 * 24; // ms const sessionStore = MongoStore.create({ mongoUrl: "mongodb://localhost:27017/zooit", collection: "sessions" }); // 直接创建session中间件实例,不要包一层函数 const sessionMiddleware = expressSession({ secret: process.env.SECRET_KEY, resave: false, saveUninitialized: true, store: sessionStore, cookie: { maxAge: day * 30 } }); // express中直接使用实例 app.use(sessionMiddleware);
2. 修正socket.io中间件调用
直接用上面创建的中间件实例处理socket握手请求:
io.use((socket, next) => { // 调用session中间件,第二个参数为空对象模拟response即可 sessionMiddleware(socket.request, {}, next); }); // 仅保留connection事件的全局监听 io.on("connection", require("./socket-controllers/onConnect"));
3. 修正disconnect事件监听位置
disconnect是单连接级别的事件,需要放到onConnect逻辑中绑定到当前socket实例:
// onConnect.js function onConnect(socket) { console.log(`User connected: ${socket.request.session}`); // 绑定当前连接的断开事件 socket.on("disconnect", () => { // 你的断开连接处理逻辑 console.log(`User disconnected: ${socket.request.session}`); }); }
额外注意事项
如果前后端部署在不同域名/端口,需要开启跨域凭证配置:
- 前端socket.io连接时开启
withCredentials:import { io } from "socket.io-client"; const socket = io("你的后端服务地址", { withCredentials: true }); - 后端CORS配置要允许对应前端源,同时开启
credentials: true。
内容的提问来源于stack exchange,提问作者Alexander Hunter
相关产品推荐
相关产品推荐

