为了账号安全,请及时绑定邮箱和手机立即绑定

结合express-session中间件理解Session和cookie的概念

在我的前端开发工程师应该知道的http协议知识这篇手记中介绍了http协议的基本知识,这一篇来讲一下cookie这个http协议中的重要概念,然后还是结合项目实际看看这个项目中如何应用了cookie。

会话(Session)

要理解cookie的作用,首先要了解会话的概念。

会话是一种持久的网络协议,用于完成服务器和客户端之间的一些交互行为。会话是一个比连接粒度更大的概念,一次会话可能包含多次连接,每次连接都被认为是会话的一次操作。

在Web中,Session是指一个用户与网站服务器进行一系列交互的持续时间,通常指从注册进入系统到注销退出系统之间所经过的时间,以及在这段时间内进行的操作,还有,服务器端为保存用户状态开辟的存储空间。

http协议的无状态性

每条http请求/响应是互相独立的,服务器并不知道两条http请求是同一用户发送的还是不同的用户发送的,就好比生活中常见的饮料自动贩售机,投入硬币,选择饮料,然后饮料出来,买饮料的人拿到饮料,整个过程中贩售机只负责识别要买的是哪种饮料并且给出饮料,并没有记录是哪个人买的,以及某个人买了哪几种,每种买了几瓶。如果考虑现在的购物网站的购物车功能,记录用户状态就很有必要了,这就需要用到会话,而http协议由于本身的无状态性就需要cookie来实现会话。

cookie的概念

简单的说,cookie是服务器发给用户的一个标识,用来帮助服务器识别用户,从而记录用户状态。

cookie 是当前识别用户,实现持久会话的最好方式。cookie 中包含了一个由名字= 值(name=value)这样的信息构成的任意列表

用户第一次访问网站时,服务器对用户没有任何了解,于是通过http响应给用户发送一个cookie,让浏览器存下来,浏览器记住这个cookie之后,用户再向这个网站发送http请求的时候就带上这个cookie,服务器收到这个cookie后就能识别出这个特定的用户,从而通过查询服务器数据库中为这个用户积累的一些特定信息来给用户一些个性化服务。

前面说到会话是某个特定用户和网站一系列交互的过程,也就是说在会话过程中,用户可能会通过浏览器向服务器发送许多个http请求。

为了实现会话,服务端需要一个会话标识ID能保存到浏览器,让它在后续的请求时都带上这个会话标识ID,以便让服务端知道某个请求属于哪个会话,这样便可以维护与会话相关的状态数据(比如用户登录状态)。由于Cookie对于用户来说,是个不可见的东西,而且每次请求都会传递到 服务端,所以它就是很理想的会话标识ID的保存容器。

Session和cookie在基于express框架项目中的应用

在Express的会话中间件express-session中,就是用cookie来保存sessionID的。可以在app.js中引入express-session中间件:

app.use(session({
    // secret用来防止篡改 cookie
  secret: settings.cookieSecret,
  resave: false,
  saveUninitialized: false,
  key: settings.db,//cookie name
  cookie: {maxAge: 1000 * 60 * 60 * 24 * 30},//30 days,cookie 的生存期,毫秒为单位,过期后cookie的sessionID就自动删除了
  // store选项设置会话存储实例
  // 设置它的 store 参数为 MongoStore 实例,把会话信息存储到数据库中,以避免丢失
  store: new MongoStore({
    url: settings.url
  })
}));

上述代码中的cookie项即是用来存储sessionID的,在express-session这个中间件中,存储sessionID的cookie的名字是connet.sid。

还是打开这个项目的网址http://demo-bootstrap-blog.herokuapp.com/,然后登陆,用fiddler或者firebug可以看到/login这个POST请求的response header部分有如下头域:

Set-Cookie: connect.sid=s%3AIoelz0ok49NS6GmWfu3irUj***7XU9.LKB%2BH38XHSnLKyYLk5oGLgyKLYHR4Nr5IGOIC6m2Oeg; Path=/; Expires=Sat, 10 Dec 2016 14:35:44 GMT; HttpOnly

当登录网站的时候,服务端就创建了一个session,把sessionID存在connect.sid这一cookie值中,然后通过Set-Cookie这个响应头把sessionID发回给浏览器,接着跳转到/index路径,在/index这个GET请求的request header部分可以看到

Cookie: connect.sid=s%3AIoelz0ok49NS6GmWfu3irUj***7XU9.LKB%2BH38XHSnLKyYLk5oGLgyKLYHR4Nr5IGOIC6m2Oeg

也就是说,浏览器通过cookie把这个sessionID存了下来,又通过这个http请求把刚才收到的cookie值也就是sessionID发回给了服务器,服务器就能识别出这个http请求还是同一个用户的会话。

创建了会话之后,就可以通过req.session 获取当前用户的会话对象(这个对象是存在服务端数据库中的),比如这个项目中,用户注册或者登陆以后就把user对象存到req.session.user中,登出时则req.session.user = null;,从而可以通过req.session.user判断用户的登录状态,控制用户访问页面的权限。

PS:cookie的分类

注意到上面的代码在cookie项中设置了maxAge属性,值是30天,意思是这个cookie的有效期是30天,30天后这个cookie就过期了会自动删除,在express-session这个中间件里还可以用expires这个属性来设置过期时间,值就是一个具体的日期,如果maxAge和expires属性都设置了,写在后面的一个会被采用。

  • 持久cookie:像上面这样设置了过期时间的cookie是持久cookie,会存在硬盘中(不同浏览器不一样),在firebug的cookie面板中可以看到在过期时间一栏,显示了一个具体日期,就是30天以后,也可以在firefox浏览器的菜单栏工具页面信息安全查看cookie里看到cookie的具体信息。
  • 会话cookie:假如把上面代码中的maxAge属性删掉或者设为null,就变成了会话cookie,会话cookie是临时的,关闭浏览器之后就没有了。我也亲自验证了一下:

    首先要把之前存下来的持久cookie删掉,在firebug里的cookie面板里相应的cookie上点击鼠标右键然后在弹出的菜单里选择删除,或者在菜单栏工具页面信息安全查看cookie也可以删除当前页面网站的cookie,然后登出,ctrl+F5强制刷新页面,这时在firebug的cookie面板里可以看到是没有cookie的,接着登录,再看cookie面板,就能看到cookie了,并且过期时间一栏显示的不再是具体日期,而是“会话”,接着我登出,相同的cookie还是存在,接着我关闭标签页,然后再新建标签页,打开http://demo-bootstrap-blog.herokuapp.com/,发现相同的cookie还是存在,最后我关闭浏览器,然后再重新打开浏览器,打开http://demo-bootstrap-blog.herokuapp.com/,再看cookie一栏,发现cookie没有了,这就说明上面的cookie就是一个临时的会话cookie,关闭浏览器以后会话cookie就被删除了。

在这个项目里我使用了持久cookie,这样用户关闭浏览器之后,再打开浏览器访问这个项目网站就能继续之前的会话了。


总结

http协议只完成请求和响应的工作,不能记录用户状态,服务器为了记录用户状态,跟踪用户行为,从而提供个性化服务而引入session,用户的一系列交互行为都包含在session内,用户状态信息也存储在服务器端为session开辟的一个存储空间内;当用户通过浏览器发送一系列http请求时,为了识别这些请求属于哪个session,服务端需要给每个session一个sessionID,cookie就是浏览器端用来存储和发送这个sessionID的。


参考资料
  1. Node.js开发指南
  2. HTTP无状态协议与session原理
  3. 浅谈HTTP的无状态性
  4. HTTP权威指南
  5. 细说cookie
  6. express-session——npm

本作品采用知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。要查看该许可协议,可访问 http://creativecommons.org/licenses/by-nc-sa/4.0/ 或者写信到 Creative Commons, PO Box 1866, Mountain View, CA 94042, USA。

点击查看更多内容
4人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
83
获赞与收藏
479

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消