Socket.io单例类加Passport鉴权中间件后connect事件不触发问题
问题原因
出现该问题是以下几个常见错误共同导致的:
- 中间件转换函数
wrap实现错误:express风格中间件的入参为(req, res, next),你当前写的wrap函数给第二个参数传了空对象{},session、passport中间件执行时需要调用res对象的方法,无对应方法会导致中间件阻塞,永远不会调用next(),自然无法触发后续的connect事件。 - session配置不互通:你在SocketManager中单独初始化了一个session中间件,和express主服务使用的session中间件如果不是同一个实例、或者store/secret配置不一致,会导致两边session无法共享,已登录用户的session在Socket请求中识别不到,被最后一个鉴权中间件直接拒绝,且你没有监听连接错误,所以看不到报错,误以为
connect事件没有触发。 - 跨域场景下凭证传递缺失:如果你的前后端是跨域部署,Socket服务端没有配置允许凭证、客户端没有开启凭证传递,会导致session cookie无法带到后端,鉴权失败连接被拒绝。
解决方案
按以下步骤依次修改即可:
- 修复
wrap函数的实现,补充最小可用的mock res对象:
const wrap = middleware => (socket, next) => { // 模拟express res的核心方法,满足中间件执行要求 const mockRes = { end: () => {}, setHeader: () => {}, getHeader: () => {}, writeHead: () => {} } middleware(socket.request, mockRes, next); };
- 统一session中间件实例,不要在SocketManager内单独初始化session
- 先在express主服务(app.js)中定义session中间件并导出:
// app.js中新增 const session = require('express-session'); // 注意这里的配置要和你原来express用的完全一致,如果你用了第三方store比如connect-mongo也要同步配置 exports.sessionMiddleware = session({ secret: 'MySecrectKey', resave: true, saveUninitialized: true }); app.use(exports.sessionMiddleware);
- 然后在socketClass.js中导入这个公共的session中间件使用,删除原来内部初始化的sessionMiddleware代码
- 跨域场景补充CORS配置
- Socket服务端初始化时添加CORS配置:
this.io = new Server(server, { cors: { origin: "你的前端实际访问地址,比如http://localhost:5173", // 不能用*,必须指定具体地址 credentials: true } });
- 客户端Socket初始化时开启凭证传递:
const socket = io('服务端地址', { withCredentials: true });
- 添加连接错误监听,方便后续排查问题
在app.js的io.on('connect')前添加错误监听代码:
io.on('connection_error', (err) => { console.log('Socket连接失败原因:', err.message); });
修改完成后先确认用户已经在web端通过passport的登录接口完成登录,再发起Socket连接即可正常触发connect事件。
内容的提问来源于stack exchange,提问作者Ace
相关产品推荐
相关产品推荐

