var Cookie = module.exports = function Cookie(options) {
this.path = '/';
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那么就是用户指定的值
};
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 = options.name || options.key || 'connect.sid' //很显然cookie的name默认是connect.sid,而且首先获取到的name而不是key r cookieId = req.sessionID = getcookie(req, name, secrets);
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();
});
};
};
function isSaved(sess) {
return originalId === sess.id && savedHash === hash(sess);
}
rollingSessions = options.rolling || false;//默认为false
//这个方法用户判断是否需要在请求头中设置cookie
// determine if cookie should be set on response
function shouldSetCookie(req) {
// cannot set cookie without a session ID
//如果没有sessionID直接返回,这时候不用设置cookie
if (typeof req.sessionID !== 'string') {
return false;
}
//var cookieId = req.sessionID = getcookie(req, name, secrets);
return cookieId != req.sessionID
? saveUninitializedSession || isModified(req.session)
//rollingSessions = options.rolling || false,其中rolling表示sessionCookie在每一个响应中都应该被发送。也就是说如果用户设置了rolling即使sessionID没有被修改
//也依然会把session的cookie发送到浏览器
: rollingSessions || req.session.cookie.expires != null && isModified(req.session);
}
var saveUninitializedSession = options.saveUninitialized;
/如果用户不指定saveUninitializedSession那么提示用户并设置saveUninitializedSession为true
if (saveUninitializedSession === undefined) {
deprecate('undefined saveUninitialized option; provide saveUninitialized option');
saveUninitializedSession = true;
}
// determine if session should be saved to store
//判断是否需要把session保存到到store中
function shouldSave(req) {
// cannot set cookie without a session ID
if (typeof req.sessionID !== 'string') {
debug('session ignored because of bogus req.sessionID %o', req.sessionID);
return false;
}
// var saveUninitializedSession = options.saveUninitialized;
// var cookieId = req.sessionID = getcookie(req, name, secrets);
return !saveUninitializedSession && cookieId !== req.sessionID
? isModified(req.session)
: !isSaved(req.session)
}
//这个方法用户判断是否需要在请求头中设置cookie
// determine if cookie should be set on response
function shouldSetCookie(req) {
// cannot set cookie without a session ID
//如果没有sessionID直接返回,这时候不用设置cookie
if (typeof req.sessionID !== 'string') {
return false;
}
//var cookieId = req.sessionID = getcookie(req, name, secrets);
return cookieId != req.sessionID
? saveUninitializedSession || isModified(req.session)
//rollingSessions = options.rolling || false,其中rolling表示sessionCookie在每一个响应中都应该被发送。也就是说如果用户设置了rolling即使sessionID没有被修改
//也依然会把session的cookie发送到浏览器
: rollingSessions || req.session.cookie.expires != null && isModified(req.session);
}
var secret = options.secret;
//unsetDestroy表示用户是否指定了unset参数是destroy,是布尔值
if (Array.isArray(secret) && secret.length === 0) {
throw new TypeError('secret option array must contain one or more strings');
}
//保证secret保存的是一个数组,即使用户传入的仅仅是一个string
if (secret && !Array.isArray(secret)) {
secret = [secret];
}
//必须提供secret参数
if (!secret) {
deprecate('req.secret; provide secret option');
}
//作用:用于从请求对象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;
}
// 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)
}
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;
'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;
};
//如果用户指定了unset,但是unset不是destroy/keep,那么保存
if (options.unset && options.unset !== 'destroy' && options.unset !== 'keep') {
throw new TypeError('unset option must be "destroy" or "keep"');
}
// TODO: switch to "destroy" on next major
var unsetDestroy = options.unset === 'destroy';
// determine if session should be destroyed
//sessionID还存在,但是req.session已经被销毁了
function shouldDestroy(req) {
// var unsetDestroy = options.unset === 'destroy';
return req.sessionID && unsetDestroy && req.session == null;
}
var app = express()
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
var app = express()
var sess = {
secret: 'keyboard cat',
cookie: {}
}
if (app.get('env') === 'production') {
app.set('trust proxy', 1) // trust first proxy
sess.cookie.secure = true // serve secure cookies
}
app.use(session(sess))
// Use the session middleware
app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
// Access the session as req.session
app.get('/', function(req, res, next) {
var sess = req.session//用这个属性获取session中保存的数据,而且返回的JSON数据
if (sess.views) {
sess.views++
res.setHeader('Content-Type', 'text/html')
res.write('<p>views: ' + sess.views + '</p>')
res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>')
res.end()
} else {
sess.views = 1
res.end('welcome to the session demo. refresh!')
}
})
session:
//req.session域下面保存的是一个Session实例,其中有cookie表示是一个对象
Session {
//这里是req.session.cookie是一个Cookie实例
cookie:
{ path: '/',
_expires: Fri May 06 2016 15:44:48 GMT+0800 (中国标准时间),
originalMaxAge: 2591999960,
httpOnly: true },
flash: { error: [Object]
}
}
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
};
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);
}
};
req.session.destroy(function(err) {
// cannot access session here
})
req.session.reload(function(err) {
// session updated
})
req.session.save(function(err) {
// session saved
})
function Session(req, data) {
Object.defineProperty(this, 'req', { value: req });
Object.defineProperty(this, 'id', { value: req.sessionID });
if (typeof data === 'object' && data !== null) {
// merge data into this, ignoring prototype properties
for (var prop in data) {
if (!(prop in this)) {
this[prop] = data[prop]
}
}
}
}
//重置".cookie.maxAge"防止在session仍然存活的时候cookie已经过期了
defineMethod(Session.prototype, 'touch', function touch() {
return this.resetMaxAge();
});
//resetMaxAge方法,用于为cookie的maxAge指定为cookie的originalMaxAge
defineMethod(Session.prototype, 'resetMaxAge', function resetMaxAge() {
this.cookie.maxAge = this.cookie.originalMaxAge;
return this;
});
function Session(req, data) {
Object.defineProperty(this, 'req', { value: req });
Object.defineProperty(this, 'id', { value: req.sessionID });
if (typeof data === 'object' && data !== null) {
// merge data into this, ignoring prototype properties
for (var prop in data) {
if (!(prop in this)) {
this[prop] = data[prop]
}
}
}
}
//重写了Object对象的defineProperty,其中defineProperty用于为这个对象指定一个函数,其中第二个参数是函数的名称,第三个是函数本身
function defineMethod(obj, name, fn) {
Object.defineProperty(obj, name, {
configurable: true,
enumerable: false,
value: fn,
writable: true
});
};
var hour = 3600000 req.session.cookie.expires = new Date(Date.now() + hour) req.session.cookie.maxAge = hour//和上面的expires等价
function MemoryStore() {
Store.call(this)
this.sessions = Object.create(null)
}
//继承了Store中的所有的原型属性
util.inherits(MemoryStore, Store)
//通过指定的sessionId获取当前的session对象,然后把这个对象的cookie更新为新的session对应的cookie,同时sessions中的当前session也进行更新(包括过期时间等)
MemoryStore.prototype.touch = function touch(sessionId, session, callback) {
var currentSession = getSession.call(this, sessionId)
if (currentSession) {
// update expiration
currentSession.cookie = session.cookie
this.sessions[sessionId] = JSON.stringify(currentSession)
}
callback && defer(callback)
}
session({
secret: settings.cookieSecret,
//blog=s%3AisA3_M-Vso0L_gHvUnPb8Kw9DohpCCBJ.OV7p42pL91uM3jueaJATpZdlIj%2BilgxWoD8HmBSLUSo
//其中secret如果是一个string,那么就是用这个string对sessionID对应的cookie进行签名,如果是一个数组那么只有第一个用于签名,其他用于浏览器请求后的验证
key: settings.db,
//设置的cookie的名字,从上面可以看到这里指定的是blog,所以浏览器的请求中可以看到这里的sessionID已经不是sessionID了,而是这里的blog
name:"qinliang",//name的优先级比key要高,如果同时设置了那么就是按照name来制定的
//没有name时候response中为:set-cookie:blog=s%3A6OJEWycwVMmTGXcZqawrW0HNLOTJkYKm.0Slax72TMfW%2B4Tiit3Ox7NAj5S6rPWvMUr6sY02l0DE; Path=/; Expires=Thu, 28 Apr 2016 10:47:13 GMT; HttpOnly
//当有name的时候resopnse中:set-cookie:qinliang=s%3ABDOjujVhV0DH9Atax_gl4DgZ4-1RGvjQ.OeUddoRalzB4iSmUHcE8oMziad4Ig7jUT1REzGcYcdg; Path=/; Expires=Thu, 28 Apr 2016 10:48:26 GMT; HttpOnly
resave:true,//没有实现touch方法,同时也设置了session的过期时间为30天
rolling:true,//如果设置了rolling为true,同时saveUninitialized为true,那么每一个请求都会发送没有初始化的session!
saveUninitialized:false,//设置为true,存储空间浪费,不允许权限管理
cookie:
{
maxAge: 1000 * 60 * 60 * 24 * 30
},
//cookie里面全部的设置都是对于sessionID的属性的设置,默认的属性为{ path: '/', httpOnly: true, secure: false, maxAge: null }.
//所以最后我们保存到数据库里面的信息就是:{"cookie":{"originalMaxAge":2592000000,"expires":"2016-04-27T02:30:51.713Z","httpOnly":true,"path":"/"},"flash":{}}
store: new MongoStore({
db: settings.db,
host: settings.host,
port: settings.port
})
})
function unsigncookie(val, secrets) {
for (var i = 0; i < secrets.length; i++) {
var result = signature.unsign(val, secrets[i]);
if (result !== false) {
return result;
}
}
return false;
}
// var cookieId = req.sessionID = getcookie(req, name, secrets);
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
//如果从req.headers.cookie中没有读取到session ID的数据,那么就去cookie parser的req.signedCookies中读取
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
//如果req.signedCookies中也没有获取到数据那么直接从req.cookies中获取
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;
}
var Session = require('./session/session')
, MemoryStore = require('./session/memory')
, Cookie = require('./session/cookie')
, Store = require('./session/store')
var cookieOptions = options.cookie || {};
function generateSessionId(sess) {
return uid(24);
}
// generates the new session
store.generate = function(req){
req.sessionID = generateId(req);//产生一个sessionID
req.session = new Session(req);//产生一个Session
req.session.cookie = new Cookie(cookieOptions);//在req.session对象的cookie域下面保存的是一个Cookie对象
if (cookieOptions.secure === 'auto') {
req.session.cookie.secure = issecure(req, trustProxy);
}
};
var Cookie = module.exports = function Cookie(options) {
this.path = '/';
this.maxAge = null;
this.httpOnly = true;
//最终的this就是这个新创建的Cookie具有这些默认的属性,同时还具有用户自己传入的options参数,如用户传入的var cookieOptions = options.cookie || {};
//也就是用户传入的options.cookie属性
if (options) merge(this, options);
/*这个utils.merge的源码只有一句话:
exports = module.exports = function(a, b){
if (a && b) {
for (var key in b) {
a[key] = b[key];
}
}
return a;
};*/
this.originalMaxAge = undefined == this.originalMaxAge
? this.maxAge
: this.originalMaxAge;
//默认的originalMaxAge就是this.maxAge也就是null,如果指定了originalMaxAge那么就是用户指定的值
};
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有