除非你在客户端设置了一些事件来通知服务器窗口正在关闭,否则服务器将无法知道会话不再被使用。
您想在精神上将会话视为两个部分。一部分是在节点和浏览器之间传递的令牌(cookie)。第二个是存储中会话的实际持久性(基本的 MemoryStore 或 Redis,或者您的另一个数据库的新会话存储)。所有连接会话代码所做的就是将这些与每个请求进行匹配。
- 检查会话 cookie
- 如果存在,请尝试在商店中查找
- 使从存储中检索到的数据可用于请求
- 在请求结束时,更新 cookie 的 TTL 信息
- 将会话写回存储
请注意,除非您使用 MemoryStore,否则 Node 不会在内存中保存会话数据,除非您的请求正在对它进行操作。(好吧,它会在内存中存在一段时间,但不会被引用并受到垃圾回收的影响)。当您考虑各种部署方案时,这是有道理的。
因此,服务器端会话到期的工作落到了 Store 本身。Redis 之所以如此出色的原因之一是因为它自动管理过期的东西,你可以在它的 set 操作connect-redis
中看到这样做:
RedisStore.prototype.set = function(sid, sess, fn){
sid = this.prefix + sid;
try {
var maxAge = sess.cookie.maxAge
, ttl = this.ttl
, sess = JSON.stringify(sess);
ttl = ttl || ('number' == typeof maxAge
? maxAge / 1000 | 0
: oneDay);
debug('SETEX "%s" ttl:%s %s', sid, ttl, sess);
this.client.setex(sid, ttl, sess, function(err){
err || debug('SETEX complete');
fn && fn.apply(this, arguments);
});
} catch (err) {
fn && fn(err);
}
};
您可以看到它将 TTL 除以 1000,因为它使用秒而不是毫秒来表示其到期时间。最流行的 MongoDB 会话存储以相同的方式使用 MongoDB 的 TTL 功能。
所以这是一个很长的说法,你要么依赖你的数据库引擎来自动提供服务器端的会话过期,要么你需要自己实现过期。您可以在节点应用程序之外有一个进程(可能是另一个节点进程)来执行它,或者您的商店实现可以安装一个 SetInterval 任务来定期检查和清理它。例如,基于 MySQL 的会话存储就是这样做的
关于你问题的第二部分,在length
做clear
什么?评论者说 RedisStore 没有实现这些是正确的,它们可能会被安全地忽略,但是您可以在MemoryStore 源代码中看到它们的实现。不太令人兴奋。
clear
如果提供了回调,则清空所有会话和回调:
MemoryStore.prototype.clear = function(fn){
this.sessions = {};
fn && fn();
};
length
只需使用商店中的会话数回调:
MemoryStore.prototype.length = function(fn){
fn(null, Object.keys(this.sessions).length);
};
希望这会有所帮助。