是的,我已经仔细阅读了文档,该文档写得很好: Socket IO Cheatsheet
这是问题所在:当Express App中的会话被销毁时,我想通知用户注销。现在发生了什么:当我从会话中注销时,所有其他客户端(包括那些已经登录或尚未登录的客户端)都会收到一条消息,指出他们已注销。是的,我的快速应用程序运行良好-它们没有注销,但是我相信SOCKET IO会向他们发送消息。我运行了调试器,事实证明这两个客户端也是可区分的。
这是我的代码:
server.js:
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
app.set('socketio', io);
io.on('connection', function (socket) {
app.set('current_socket', socket);
console.log('No of clients:', io.engine.clientsCount);
});
userController.js:
exports.userLogout = function(req, res, next) {
const sessionID = req.session.id;
const io = req.app.get('socketio');
const this_socket = req.app.get('current_socket');
req.session.destroy(function (err){
if(err) {
console.error("userLogout failed with error:", err);
return next(err);
}
else {
console.log("this_socket:", this_socket);
console.log("io:", io);
this_socket.emit('userAction', { action: 'logout' });
//other logic to remove old sessions from DB Session Store
//and finally:
res.status(200)
.json({
status: 'success',
api_data: {'loggedIn':false},
message: 'Logout successful.'
});
}
}
}
我什至尝试这样做:
io.emit('userAction', { action: 'logout' });
但是事实证明它仍然会发送给所有客户端。我很确定某个地方不匹配,只是不知道在哪里。
答案 0 :(得分:2)
如果要向特殊用户发送发射,则需要为每个会话ID创建空间
io.on('connection', function (socket) {
app.set('current_socket', socket);
var sessionId = socker.request.session.id
//join room
socket.join(sessionId);
});
userController.js:
exports.userLogout = function(req, res, next) {
const sessionID = req.session.id;
const io = req.app.get('socketio');
const this_socket = req.app.get('current_socket');
req.session.destroy(function (err){
if(err) {
console.error("userLogout failed with error:", err);
return next(err);
}
else {
console.log("this_socket:", this_socket);
console.log("io:", io);
this_socket.sockets.in(sessionID).emit('userAction', { action: 'logout' });
//other logic to remove old sessions from DB Session Store
//and finally:
res.status(200)
.json({
status: 'success',
api_data: {'loggedIn':false},
message: 'Logout successful.'
});
}
}
}
答案 1 :(得分:1)
您必须为每个用户定义唯一的套接字对象。我们有很多方法可以做到这一点。
以简单的方式,我们使用用户ID(唯一)作为存储套接字对象的键(映射方式:key(userId)-vaule(socketObj))。
跟随兔子:
用户登录后,客户端向服务器端发出一个事件(登录),该事件包括用户ID。
客户端:
[HttpPost("InserUsers")]
public async Task<List<ApiResponseMessage>> InserUsers()
{
List<User> users = new List<User> {
new User{ Name = "Jack" },
new User{ Name = "Tom"},
new User{ Name = "Tony"}
};
List<ApiResponseMessage> list = new List<ApiResponseMessage>();
foreach (var user in users)
{
var response = Insert(user);
list.Add(new ApiResponseMessage
{
Content = new { user },
ReasonPhrase = response.ReasonPhrase,
StatusCode = response.StatusCode
});
}
return list;
}
public ApiResponseMessage Insert(User user)
{
// do insert and if there is error
if (user.Name == "Tom")
{
return new ApiResponseMessage()
{
StatusCode = HttpStatusCode.BadRequest,
ReasonPhrase = $"Error"
};
}
else
{
return new ApiResponseMessage()
{
StatusCode = HttpStatusCode.OK,
ReasonPhrase = $"Successfully inserted"
};
}
}
服务器端:
// login success
socket.emit('userLoggedIn', {userId: THE_USER_ID})
userController.js:
io.on('connection', function (socket) {
// app.set('current_socket', socket);
console.log('No of clients:', io.engine.clientsCount);
socket.on('userLoggedIn', function(data) => {
app.set(data.userId, socket); // save socket object
})
});