admin 管理员组

文章数量: 1087652

浅谈cookie 和 session【彻底弄明白】

        我们先假设一个开发场景,我们要通过账号登录来记录不同的用户,该用户发表过哪些文章等等,但是我们要怎么来区分不同的用户账号呢?

一. cookie

        这时就需要引入了我的 cookie , http 本是一个无状态的协议,但是在其请求头中加入 cookie,就使得我们的浏览器可以辨识不同的用户。第一次登录在后端匹配其用户账号密码登录成功后,在其响应头中为其设置 cookie 值, 将识别该用户的唯一值保存在 cookie 中,之后的每次请求都会在请求头中携带该值,可以标识用户。

  设置 Cookie 的所有参数值 

res.setHeader('Set-Cookie', [key, value]) ;

有些同学会想,这不就相当于一个缓存吗,我也可以使用 localStorage 保存一个该用户身份,每次使用 POST 请求携带该身份也可以识别用户。确实如此可以实现同样的效果,但是变得复杂了很多。

        首先每次请求需要使用 POST 请求 手动 携带该值,在服务器端每次获取该值要解析报文体,这就浪费了开销,并且该身份可以在前端人为修改,你就可以访问任何用户的任何信息,安全性很低。相比 cookie ,我们只需要设置一次,之后所有请求都会自动携带该值,但是 cookie 同样也可以在前端访问得到,也可以进行修改,因此单独用 cookie 来作为用户唯一识别也是不可行,其安全性也会受到威胁,我们只能用其保留一些其他不需要考虑安全性的数据。

cookie 性能问题:

        由于 cookie 的实现机制,一旦服务器向客户端发送了设置 cookie 的意图,除非 cookie 过期,否则客户每次请求都会发送这些 cookie 到服务器,一旦设置 cookie 较多导致报头较大,因此需要优化其使用:

  • 减小 cookie 大小:如果在域名根节点设置 cookie,那么其所有子路径下的请求都会携带这些cookie,那么在不需要 cookie 的请求中携带 cookie 就显得那么多此一举了。
  • 为静态组件使用不同的域名:也就是说为不需要 cookie 的组件换个域名,可以降低cookie的无效传输

既然 cookie 不是最理想的标识用户的办法,那么我们就引入了 session 的使用。

二. session

        cookie 虽然可以实现状态记录,但是并不是那么完美,为了解决 cookie 敏感数据问题, session 应运而生,由于 session 只保留在服务器端,客户端无法修改,这样数据的安全性就得到了保障。

  • 基于 cookie 来实现用户和数据的映射

        分析:将所有数据放在 cookie 中不可取,但是将口令放在 cookie 中还是可行的,在sessions 中存放 session,将 key 保存在 cookie 中, key 与 value 其映射关系放在sessions 中,一旦cookie 被更改,就失去了映射关系,需要重新获取 session。

      ① 生成 session

        其中 key 是cookie 中保存口令的键值,用来存放 session.id ,来获取对应 session。

// 手动获取session
let createsession = function() {return {key: 's',  // 随意设置,对应的 cookie 保存口令get() {let session = {};session.id = (new Date()).getTime() + Math.random();session.cookie = {expire : (new Date()).getTime() + EXPIRES // EXPIRES 为过期时间}sessions[session.id] = session;return session;},isOverTime( session ) {return session.cookie.expire < (new Date()).getTime()}}
}();

        ②  设置 cookie

        将生成的 session.id 设置为 cookie 值,在每次请求中携带。

let setSession = function(req, res) {let cookies = [];cookies.push(req.headers.cookie);let session = createsession.key+ '=' + req.session.id;cookies.push(session);res.setHeader('Set-Cookie', cookies);
}

        ③ 用来获取校验并获取session值

    let cookie = parseCookie(req.headers.cookie);console.log(cookie)let id = cookie[createsession.key];if(!id) { console.log('获取session') req.session = createsession.get();}else{console.log('有 session')let session = sessions[id];if( session ) {if(createsession.isOverTime(session)){// 过期console.log('过期')delete sessions[id];}else{// 更新时间console.log('更新过期时间')session.cookie.expire = (new Date()).getTime() + EXPIRES;req.session = session;}}else {console.log('重新获取session')//  session 过期或口令不对req.session = createsession.get();}}

        ④ 用 session 来存放信息

let handleEvent = function(req, res) {setSession(req, res);if(!req.session.user){req.session.user = '石头山';res.send('你好我叫石头山');}else{res.send('我知道你是' + req.session.user);}
}
  • 通过查询字符串来实现 session (感兴趣的可以自己查阅,因为应用不多不做解释)

        这样我们就实现了在session中保存 数据,这种方法比在 Cookie 中直接保存安全很多,这种依赖Cookie 的实现是目前大多数 Web 使用方案。

session性能问题:

这种方式将 session 信息全部保存到服务器中,随着用户不断增多,可能很快会内存上限,并频繁检验 session 过期进行垃圾回收,严重影响性能,因此我们需要将 session 集中管理,目前常用的工具是 Redis,Memcached 等。

三. 总结

cookie 与 session 区别:

  • cookie 保存在服务器和前端中,而 session 只保存在服务器中

我们使用时,千万不要把 cookie 当成缓存使用,造成不必要的浪费,通过合理控制 session 的过期时间。

本文标签: 浅谈cookie 和 session彻底弄明白