//作用:用于从请求对象request中获取session ID值,其中name就是我们在options中指定的,首先从req.headers.cookie获取,接着从req.signedCookies中获取,最后从req.cookies获取 function getcookie(req, name, secrets) { var header = req.headers.cookie; var raw; var val; // read from cookie header if (header) { var cookies = cookie.parse(header); raw = cookies[name]; if (raw) { if (raw.substr(0, 2) === 's:') { //切割掉前面的字符"s:"! val = unsigncookie(raw.slice(2), secrets); //val表示false意味着客户端传递过来的cookie被篡改了! if (val === false) { debug('cookie signature invalid'); val = undefined; } } else { debug('cookie unsigned') } } } // back-compat read from cookieParser() signedCookies data if (!val && req.signedCookies) { val = req.signedCookies[name]; if (val) { deprecate('cookie should be available in req.headers.cookie'); } } // back-compat read from cookieParser() cookies data if (!val && req.cookies) { raw = req.cookies[name]; if (raw) { if (raw.substr(0, 2) === 's:') { val = unsigncookie(raw.slice(2), secrets); if (val) { deprecate('cookie should be available in req.headers.cookie'); } if (val === false) { debug('cookie signature invalid'); val = undefined; } } else { debug('cookie unsigned') } } } return val; }
getcookie方法用于从请求中获取sessionID进行解密,作为秘钥。
// setcookie(res, name, req.sessionID, secrets[0], cookie.data); //方法作用:为HTTP响应设置cookie,设置的cookie是把req.sessionID进行加密过后的cookie,其中name用于保存到客户端的sessionID的cookie的名称 function setcookie(res, name, val, secret, options) { var signed = 's:' + signature.sign(val, secret); //对要发送的cookie进行加密,密钥为secret var data = cookie.serialize(name, signed, options); //其中options中可能有decode函数,返回序列化的cookie debug('set-cookie %s', data); var prev = res.getHeader('set-cookie') || []; //获取set-cookie头,默认是一个空数组 var header = Array.isArray(prev) ? prev.concat(data) : Array.isArray(data) ? [prev].concat(data) : [prev, data]; //通过set-cookie,发送到客户端 res.setHeader('set-cookie', header) }
用于setcookie方法,该方法用于对sessionID用指定的秘钥进行签名。
store:保存session的地方,默认是一个MemoryStore实例
store = options.store || new MemoryStore // notify user that this store is not // meant for a production environment //如果在生产环境下,同时store也就是用户传入的store(默认为MemoryStore)是MemoryStore那么给出警告 if ('production' == env && store instanceof MemoryStore) { console.warn(warning); } // generates the new session //为用于指定的store添加一个方法generate,同时为这个方法传入req对象,在这个generate方法中为req指定了sessionID,session,session.cookie //如果用户传入的secure为auto, store.generate = function(req){ req.sessionID = generateId(req); req.session = new Session(req); req.session.cookie = new Cookie(cookieOptions); //用户指定的secure参数如果是auto,那么修改req.session.cookie的secure参数,并通过issecure来判断 if (cookieOptions.secure === 'auto') { req.session.cookie.secure = issecure(req, trustProxy); } }; //查看store是否实现了touch方法 var storeImplementsTouch = typeof store.touch === 'function'; //为store注册disconnect事件,在该事件中吧storeReady设置为false store.on('disconnect', function(){ storeReady = false; }); //为stroe注册connect事件,把storeReady设置为true store.on('connect', function(){ storeReady = true; }); // expose store req.sessionStore = store;
我们知道这个store是用于保存session的地方,默认是一个MemoryStore,但是在生产环境下不建议使用MemoryStore,同时store有很多自定义的方法,如这里就为他添加了generate,connect,disconnect,当然也包含destroy方法。如果你对store感兴趣,可以看看下面这个通用的store具有的所有的方法:
'use strict'; var EventEmitter = require('events').EventEmitter , Session = require('./session') , Cookie = require('./cookie') var Store = module.exports = function Store(options){}; //这个Store实例是一个EventEmitter实例,也就是说Store实例最后还是一个EventEmitter实例对象 Store.prototype.__proto__ = EventEmitter.prototype; //每一个store有一个默认的regenerate方法用于产生session Store.prototype.regenerate = function(req, fn){ var self = this; //regenerate底层调用的是destroy方法,第一个参数是req.sessionID,至于回调中的self.generate必须是对容器进行指定的 this.destroy(req.sessionID, function(err){ self.generate(req); fn(err);//最后回调fn }); //调用这个store的destory方法,销毁req.sessionID,销毁成功后通过刚才的store的generate方法产生一个sessionID }; //通过指定的sid加载一个Session实例,然后触发函数fn(err,sess) Store.prototype.load = function(sid, fn){ var self = this; //最后调用的是Store的get方法 this.get(sid, function(err, sess){ if (err) return fn(err); if (!sess) return fn(); //如果sess为空那么调用fn()方法 var req = { sessionID: sid, sessionStore: self }; //调用createSession来完成的 sess = self.createSession(req, sess); fn(null, sess); }); }; //从一个JSON格式的sess中创建一个session实例,如sess={cookie:{expires:xx,originalMaxAge:xxx}} Store.prototype.createSession = function(req, sess){ var expires = sess.cookie.expires , orig = sess.cookie.originalMaxAge; //创建session时候获取其中的cookie域下面的expires,originalMaxAge参数 sess.cookie = new Cookie(sess.cookie); //更新session.cookie为一个Cookie实例而不再是一个{}对象了 if ('string' == typeof expires) sess.cookie.expires = new Date(expires); sess.cookie.originalMaxAge = orig; //为新构建的cookie添加originalMaxAge属性 req.session = new Session(req, sess); //创建一个session实例,其中传入的第一个参数是req,第二个参数是sess也就是我们刚才创建的那个Cookie实例,签名为sess={cookie:cookie对象} return req.session; };