文章目录
  1. 1. cookie和session
  2. 2. Express中的cookie
  3. 3. Express中的session
    1. 3.1. 内存存储(默认)
    2. 3.2. mongodb存储
    3. 3.3. redis存储
    4. 3.4. socket.io访问session

cookie和session

Http是一个无状态协议,客户端在对服务端发送连番请求的时候,服务端无法将其连番请求统一为同一用户。
于是有了cookiesession会话。cookie采用的是在客户端保持状态的方案,它是客户端的会话状态的一种储存机制。它是服务器在本地机器上存储的小段文本或者是内存中的一段数据,并随每一个请求发送至同一个服务器。IETF RFC 2965 HTTP State Management Mechanism是通用cookie规范。网络服务器用HTTP头信息向客户端发送cookies,在客户终端,浏览器解析这些cookies并将它们保存为一个本地文件,或者本地内存中数据,它会自动将同一服务器的任何请求缚上这些cookies,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制借助于cookie机制来达到保存标识的目的,这样就可以解决HTTP协议无状态的缺陷。(摘自链接)。

Express中的cookie

由于Http的无状态特性,首先产生了cookie这种技术来解决这个问题,其作用流程如下:

1
2
3
4
* 客户端向服务端请求数据。
* 服务端想客户端发送cookie。
* 客户端保存cookie。
* 之后每次请求服务端都会自动带上cookie,直到cookie失效(浏览器关闭或者限制时间)。

我们可以对cookie进行相应的设置,设置的参数有:

1
2
3
4
* path:表示 cookie 影响到的路径,匹配该路径才发送这个 cookie。
* expires 和 maxAge:告诉浏览器这个 cookie 什么时候过期,expires 是 UTC 格式时间,maxAge 是 cookie 多久后过期的相对时间。当不设置这两个选项时,会产生 session cookie,session cookie 是 transient 的,当用户关闭浏览器时,就被清除。一般用来保存 session 的 session_id。
* secure:当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效。
* httpOnly:浏览器不允许脚本操作 document.cookie 去更改 cookie。一般情况下都应该设置这个为 true,这样可以避免被 xss 攻击拿到 cookie。

在Express4.x版本之后,session和cookies等模块不再包含在Express框架中,需要单独添加相应模块,Express中使用cookie-parser模块去操作cookie。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*app.js*/
var cookieParser = require('cookie-parser');
......
app.use(cookieParser('kiroloveyou'));

/*app.get or route.get*/
router.get('/cookie', function(req, res, next) {
if(req.cookies.user) {
console.log(req.cookies);
res.send('first time');
} else {
res.cookie('user', 'kiro', {maxAge: 60 * 1000}); //set 1min
res.send('welcome');
}
});

Express中的session

cookie 虽然很方便,但是使用 cookie 有一个很大的弊端,cookie 中的所有数据在客户端就可以被修改,数据非常容易被伪造,那么一些重要的数据就不能存放在 cookie 中了,而且如果 cookie 中数据字段太多会影响传输效率。为了解决这些问题,就产生了 session,session 中的数据是保留在服务器端的。

session 的运作通过一个 session_id 来进行。session_id 通常是存放在客户端的 cookie 中,比如在 Express 中,默认是 connect.sid 这个字段,当请求到来时,服务端检查 cookie 中保存的 session_id 并通过这个 session_id 与服务器端的 session data 关联起来,进行数据的保存和修改。

这意思就是说,当你浏览一个网页时,服务端随机产生一个 1024 比特长的字符串,然后存在你 cookie 中的 connect.sid字 段中。当你下次访问时,cookie 会带有这个字符串,然后浏览器就知道你是上次访问过的某某某,然后从服务器的存储中取出上次记录在你身上的数据。由于字符串是随机产生的,而且位数足够 多,所以也不担心有人能够伪造。伪造成功的概率比坐在家里编程时被邻居家的狗突然闯入并咬死的几率还低。

session 可以存放在 1)内存、2)cookie本身、3)redis 或 memcached 等缓存中,或者4)数据库中。线上来说,缓存的方案比较常见,存数据库的话,查询效率相比前三者都太低,不推荐;cookie session 有安全性问题,下面会提到。

Express 中操作 session 要用到 Express-session (https://github.com/Expressjs/session ) 这个模块,主要的方法就是session(options),其中 options 中包含可选参数,主要有:

1
2
3
4
5
6
7
* name: 设置 cookie 中,保存 session 的字段名称,默认为 connect.sid 。
* store: session 的存储方式,默认存放在内存中,也可以使用 redis,mongodb 等。Express 生态中都有相应模块的支持。
* secret: 通过设置的 secret 字符串,来计算 hash 值并放在 cookie 中,使产生的 signedCookie 防篡改。
* cookie: 设置存放 session id 的 cookie 的相关选项,默认为(default: { path: '/', httpOnly: true, secure: false, maxAge: null })
* genid: 产生一个新的 session_id 时,所使用的函数, 默认使用 uid2 这个 npm 包。
* rolling: 每个请求都重新设置一个 cookie,默认为 false
* resave: 即使 session 没有被修改,也保存 session 值,默认为 true

内存存储(默认)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*app.js*/
var session = require('Express-session');
......
app.use(session({
secret:'ilovekiro',
cookie:{
maxAge:30*1000
},
resave:true,
saveUninitialized: true
}));

/*app.get or route.get*/
router.get('/session', function(req, res, next) {
if(req.session.isvisit) {
console.log(req.session.id);
console.log(req.session);
req.session.count += 1;
res.send("这是你第"+req.session.count+"来访");
} else {
req.session.user = "kiro";
res.session.count = 1; //第几次访问
res.send('first time');
}
});

mongodb存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*app.js*/
var session = require('Express-session');
//自定义mongo的连接,返回 mongoose.connect('mongodb://'+dbConfig.hostname+'/'+dbConfig.database);
var mongoose = require('./db');
var MongoStore = require('connect-mongo')(session);
......
app.use(session({
secret:'ilovekiro',
cookie:{
maxAge:30*1000 //过期时间,一过期mongodb自动删除。
},
store: new MongoStore({
mongooseConnection: mongoose.connection
}),
resave:true,
saveUninitialized: true
}));

查找mongodb中数据,有以下数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
/* 0 */
{
"_id" : "RINlnX4M_VezPA2uaVVuKr1voHqvmAro",
"session" : "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"isvisit\":1}",
"expires" : ISODate("2015-07-23T04:06:33.054Z")
}

/* 1 */
{
"_id" : "SOqkAA9blNVH43yv6IpvS6HLYHWzIrCS",
"session" : "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"isvisit\":1}",
"expires" : ISODate("2015-07-23T04:06:55.943Z")
}

很好奇mongodb中如何进行定时删除操作的,查找了一下是通过创建

1
db.tests.createIndex({expires:1},{expireAfterSeconds:0})

redis存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*app.js*/
var session = require('Express-session');
var RedisStore = require('connect-redis')(session);
......
app.use(session({
secret:'ilovekiro',
cookie:{
maxAge:30*1000 //过期时间,一过期redis自动删除。
},
store: new RedisStore({
port: 6379,
host: '127.0.0.1',
}),
resave:true,
saveUninitialized: true
}));

socket.io访问session

1
2
//安装express-socket.io-session
$ npm install express-socket.io-session
文章目录
  1. 1. cookie和session
  2. 2. Express中的cookie
  3. 3. Express中的session
    1. 3.1. 内存存储(默认)
    2. 3.2. mongodb存储
    3. 3.3. redis存储
    4. 3.4. socket.io访问session