一 Cookie
因为HTTP协议是没有状态的,但很多情况下是需要一些信息的,比如在用户登陆后、再次访问网站时,没法判断用户是否登陆过。于是就有了cookies,用于在浏览器端保存用户数据,它有如下特点
1 是在客户端浏览器端才有的
2 用于记录信息,大小最大为4K字节
3 如果使用了cookies,那么任何对该域名的访问都会带上cookies
目前新型网站更多的采用浏览器缓存,cookie会存在一些问题,比如你每次往服务器提交请求时,都会带上cookie,无论是你访问的是不是静态图片。
cookie例子:
二 Session
session类似服务器端的cookie,保存于服务器端,类似于服务器缓存。用户登陆了总需要验证吧,那么就在session中验证即可,session和cookie是一一对应关系。
session的创建顺序
生成全局唯一标识符(sessionid);
开辟数据存储空间。一般会在内存中创建相应的数据结构,但这种情况下,系统一旦掉电,所有的会话数据就会丢失,如果是电子商务网站,这种事故会造成严重的后果。不过也可以写到文件里甚至存储在数据库中,这样虽然会增加I/O开销,但session可以实现某种程度的持久化,而且更有利于session的共享;
将session的全局唯一标示符发送给客户端。
问题的关键就在服务端如何发送这个session的唯一标识上。联系到HTTP协议,数据无非可以放到请求行、头域或Body里,基于此,一般来说会有两种常用的方式:cookie和URL重写。
三 Set-Cookie
Cookie是如何被设置的呢?是被服务器返回的请求设置的。
服务器会返回一个set-cookie的消息,通知浏览器要设置cookie了,于是浏览器会根据set-cookie里的字段来设置信息了,比如上图的信息就会设置session=r@rdegges.com
四 实战
我们以client-session(express-session基本完全一样)为例,为项目配置session
1 安装模块
var session = require('client-sessions');
2 配置session
app.use(session({ cookieName: 'session', secret: 'random_string_goes_here', duration: 30 * 60 * 1000, activeDuration: 5 * 60 * 1000, }));
1)secret:一个随机字符串,因为客户端的数据都是不安全的,所以需要进行加密
2) duration:session的过期时间,过期了就必须重新设置
3) activeDuration: 激活时间,比如设置为30分钟,那么只要30分钟内用户有服务器的交互,那么就会被重新激活。
五 在Session中保存用户信息
app.post('/login', function(req, res) { User.findOne({ email: req.body.email }, function(err, user) { if (!user) { res.render('login.jade', { error: 'Invalid email or password.' }); } else { if (req.body.password === user.password) { // sets a cookie with the user's info req.session.user = user; // 这里貌似有误,只是set了session,返回这个sessionid,但但数据并不会set到这个cookie里头 res.redirect('/dashboard'); } else { res.render('login.jade', { error: 'Invalid email or password.' }); } } }); });
六 Session层中间件
我们当然不希望每个请求都加上这一段,所以我们使用express来做全局配置
app.use(function(req, res, next) { if (req.session && req.session.user) { User.findOne({ email: req.session.user.email }, function(err, user) { if (user) { req.user = user; delete req.user.password; // delete the password from the session req.session.user = user; //refresh the session value res.locals.user = user; } // finishing processing the middleware and run the route next(); }); } else { next(); } });
如果用户逻辑在没有登陆时必须登陆,那我们可以继续加一个路由
function requireLogin (req, res, next) { if (!req.user) { res.redirect('/login'); } else { next(); } }; app.get('/dashboard', requireLogin, function(req, res) { res.render('dashboard.jade'); });
七 安全性
1 我们可以在登出时重置session
app.get('/logout', function(req, res) { req.session.reset(); res.redirect('https://www.jb51.net/'); });
还可以加一些安全性
httpOnly:用来保证cookie只能通过http访问,而不能用js来读取
secure:强制使用https
ephemeral:关闭浏览器时同时关闭cookie
八 总结
Cookie和session由于实现手段不同,因此也各有优缺点和各自的应用场景:
应用场景