我想使用 websockets 来跟踪用户最后一次出现的时间,以及他们当前的在线状态(如果他们当前已通过身份验证并使用应用程序)。
我有适用于应用程序某些部分的策略,因此用户将登录然后被引导到适用该策略的概述。
如果用户未通过身份验证,或者如果他们是但会话信息与数据库的信息冲突,则概览将以 notFound 响应。
如果这些简单检查通过,则用户存在,因此应创建两个事件处理程序:
- 如果会话过期前没有活动,通知客户端返回认证页面
- 当客户端断开连接时,更新他们最后一次出现的时间并改变在线状态
这是策略代码:
const schedule = require('node-schedule')
var sheduledJob
module.exports = async function isSignedIn(req, res, next) {
// If the user has not signed in, pretend the page does not exist
if (!req.session.app || !req.session.app.userId) return res.notFound()
// Store the users id
let userId = req.session.app.userId
try {
// Update the user
var users = await User.update({
id: userId
})
.set({
last_accessed: new Date().getTime(),
online: true
})
.meta({
fetch:true
})
} catch (err) {
// Handle errors
return res.serverError(err.message)
}
// If the user does not exist
if (!users || users.length !== 1) {
console.log('policies/isSignedIn: no matching user '+userId)
// Sign the user out
delete(req.session.app)
// Pretend the page does not exist
return res.notFound()
}
// When the user exists
else {
// When there is a new client connection
var io = sails.io
io.on('connection', socket => {
console.log("==> Socket Connection Established")
console.log(socket.id, socket.request.headers.cookie.replace('sails.sid=',''))
// Cancel an existing job if one exists
if (sheduledJob) sheduledJob.cancel()
// Shedule a job to notify the client when the session has expired
var d = req.session.cookie._expires
sheduledJob = schedule.scheduleJob(d, () => {
console.log('The cookie has expired')
// The client should return to the auth page (will fire disconnecting when doing so)
req.socket.emit('logout', true)
})
// When the client is disconnecting
socket.on('disconnecting', async reason => {
console.log('Client disconnecting')
// As of Sails v1.0.0-46 reason is undefined when the application is lowering
if (reason) {
try {
// Update the user
var users = await User.update({
id: userId
})
.set({
last_accessed: new Date().getTime(),
online: false
})
} catch (err) {
// Handle errors
return res.serverError(err.message)
}
}
})
})
// Proceed as the user exists and we can handle the disconnecting event
return next()
}
};
我遇到的问题是,这将在页面最初加载时起作用,但是如果我重新加载概述页面,那么我最终会得到重复的事件处理程序:
加载页面一次(记住会话年龄是 10 秒进行测试):
==> Socket Connection Established
<socketId> <sessionId>
The cookie has expired
Client disconnecting
但是如果我重新加载页面:
==> Socket Connection Established
<socketId> <sessionId>
Client disconnecting
==> Socket Connection Established
<socketId> <sessionId>
==> Socket Connection Established
<socketId> <sessionId>
The cookie has expired
Client disconnecting
Client disconnecting
因此,如果是这种情况,我认为没问题,那么也许我可以为事件侦听器创建一个命名函数,然后最初删除事件侦听器:
const schedule = require('node-schedule')
var sheduledJob
function connectionHandler(req, res, socket) {
console.log("==> Socket Connection Established")
console.log(socket.id, socket.request.headers.cookie.replace('sails.sid=',''))
...same as before...
}
module.exports = async function isSignedIn(req, res, next) {
...
// When the user exists
else {
// When there is a new client connection
var io = sails.io
var nsp = io.of('/')
nsp.removeListener('connection', connectionHandler)
io.on('connection', socket => connectionHandler(req, res, socket))
// Proceed as the user exists and we can handle the disconnecting event
return next()
}
};
但这会导致相同的重复处理程序,因此我从处理程序中删除了所有 req/res 代码:
function connectionHandler(socket) {
console.log("==> Socket Connection Established")
console.log(socket.id, socket.request.headers.cookie.replace('sails.sid=',''))
socket.on('disconnecting', async reason => {
console.log('Client disconnecting')
})
}
并在创建事件时进行了修改:
io.on('connection', connectionHandler)
结果按我的预期工作,在重新加载页面时没有创建任何重复的事件处理程序:
==> Socket Connection Established
<socketId> <sessionId>
Client disconnecting
==> Socket Connection Established
<socketId> <sessionId>
有人可以向我解释我哪里出错了,我真的不明白为什么:
io.on('connection', socket => connectionHandler(req, res, socket))
导致重复的事件处理程序,而:
io.on('connection', connectionHandler)
才不是?
如果有人可以就我在这里出错的地方或如何更好地达到预期结果提供任何建议,那么将不胜感激,非常感谢!
以下是我用来达到这一点的一些参考资料:
- https://gist.github.com/mikermcneil/6598661
- https://github.com/balderdashy/sails-docs/blob/1.0/concepts/Sessions/sessions.md#when-does-the-sailssid-change
- 如何在会话过期时断开套接字
- https://stackoverflow.com/a/5422730/2110294
- https://github.com/expressjs/session/issues/204#issuecomment-141473499
- https://stackoverflow.com/a/33308406/2110294