作用:用指定的参数创建一个session中间件,sesison数据不是保存在cookie中,仅仅sessionID保存到cookie中,session的数据仅仅保存在服务器端
警告:默认的服务器端的session存储,MemoryStore不是为了生产环境创建的,大多数情况下会内存泄露,主要用于测试和开发环境
接受的参数:
cookie:也就是session ID的cookie,默认是{ path: 'https://www.jb51.net/', httpOnly: true, secure: false, maxAge: null }.
var Cookie = module.exports = function Cookie(options) { this.path = 'https://www.jb51.net/'; this.maxAge = null; this.httpOnly = true; if (options) merge(this, options); this.originalMaxAge = undefined == this.originalMaxAge ? this.maxAge : this.originalMaxAge; //默认的originalMaxAge就是this.maxAge也就是null,如果指定了originalMaxAge那么就是用户指定的值 };
genid:产生一个新的sessionID的函数,一个返回值是string类型的函数会被作为sessionID.这个函数第一个参数是req,所以如果你想要req中的参数产生sessionID还是很不错的
默认函数是使用uid-safe这个库产生id值(产生一个算法上安全的UID,可以用于cookie也可以用于URL。和rand-token和uid2相比,后者由于使用了%导致UID产生偏态,同时可能对UID产生不必要的截断。我们的uid-safe使用的是base64算法,其函数uid(byteLength, callback)中第一个参数是比特长度而不是字符串长度)
app.use(session({ genid: function(req) { return genuuid() // use UUIDs for session IDs }, secret: 'keyboard cat' })
源码片段:
function generateSessionId(sess) { return uid(24); } var generateId = options.genid || generateSessionId; //如果用户没有传入genid参数那么就是默认使用generateSessionId函数来完成
name:在response中sessionID这个cookie的名称。也可以通过这个name读取,默认是connect.sid。如果一台机器上有多个app运行在同样的hostname+port, 那么你需要对这个sessin的cookie进行切割,所以最好的方法还是通过name设置不同的值
name = options.name || options.key || 'connect.sid' //很显然cookie的name默认是connect.sid,而且首先获取到的name而不是key r cookieId = req.sessionID = getcookie(req, name, secrets);
resave:强制session保存到session store中。即使在请求中这个session没有被修改。但是这个并不一定是必须的,如果客户端有两个并行的请求到你的客户端,一个请求对session的修改可能被另外一个请求覆盖掉,即使第二个请求并没有修改sesion。默认是true,但是默认值已经过时,因此以后default可能会被修改。因此好好研究你的需求选择一个最适用的。大多数情况下你可能需要false 最好的知道你的store是否需要设置resave的方法是通过查看你的store是否实现了touch方法(删除那些空闲的session。同时这个方法也会通知session store指定的session是活动态的),如果实现了那么你可以用resave:false,如果没有实现touch方法,同时你的store对保存的session设置了一个过期的时间,那么建议你用resave:true
var resaveSession = options.resave; if (resaveSession === undefined) { deprecate('undefined resave option; provide resave option'); resaveSession = true;//如果用户没有指定resavedSession那么默认就是true }
我们再来看看其他的逻辑
store.get(req.sessionID, function(err, sess){ // error handling //如果报错那么也会创建一个session if (err) { debug('error %j', err); if (err.code !== 'ENOENT') { next(err); return; } generate(); // no session那么就会创建一个session } else if (!sess) { debug('no session found'); generate(); // populate req.session //如果找到了这个session处理的代码逻辑 } else { debug('session found'); store.createSession(req, sess); originalId = req.sessionID; originalHash = hash(sess); //originalHash保存的是找到的这个session的hash结果,如果明确指定了resave为false那么savedHash就是原来的session的结果 if (!resaveSession) { savedHash = originalHash } wrapmethods(req.session); } next(); }); }; };
其中经过了前面的if语句后我们的savedHash就是originalHash,我们看看这个逻辑在判断这个session是否已经保存的时候再次用到了
function isSaved(sess) { return originalId === sess.id && savedHash === hash(sess); }
rolling:强制在每一个response中都发送session标识符的cookie。如果把expiration设置为一个过去的时间那么 那么过期时间设置为默认的值。roling默认是false。如果把这个值设置为true但是saveUnitialized设置为false,那么cookie不会被包含在响应中(没有初始化的session)
rollingSessions = options.rolling || false;//默认为false
我们看看rolling用于了什么环境了: