首页

11.3 开发过程

关灯 护眼    字体:

上一章 章节列表 下一章


11.3.1 会话管理的基本原理


1.什么是Session

由于HTTP是没有状态的,所以在默认情况下,如果浏览器访问了同一个网站两次,网站是不知道这两次请求来自同一个浏览器的。为了让网站知道这两次请求来自同一个网站,需要在浏览器的请求中带上一段信息。浏览器中带上的这段信息就是Cookie。

但是由于Cookie是明文存放的,任何人都能看到也能修改,所以显然不能把用户名和密码放在Cookie中,于是就需要在服务器中放一段信息,这个信息就是Session。

当用户第一次登录成功以后,网站服务器会生成一段Session。这段Session是存放在网站自己这边的,但是网站会在浏览器的 Cookie 中添加一段字符串,叫作 SessionID。由于每次浏览器请求网站时都会带上 Cookie,那么网站就可以从每一次请求中获得 SessionID。有了这个SessionID 以后,网站就可以在自己这边查询到这个请求实际对应的 Session 是什么。在解析Session里面的内容后,可以知道这个用户的用户名、什么时候登录的、账号状态等信息。

Session本质上就是网站可以理解的信息。

Session 存在哪里实际上并没有严格的要求,无论是内存中,还是文件中,或是数据库中。只要网站在需要时能够查询和理解就可以。

2.负载均衡与共享Session

由于技术的限制,一旦网站规模变大,一台服务器无论配置多么好,都无法承受同时产生的越来越多的请求,所以就有了负载均衡技术。

负载均衡技术可以在同一个域名后面接入非常多的服务器,并且自动为每一个请求选择最优的服务器。

例如,“双11”购物节,淘宝使用了数十万台服务器,但是使用淘宝购物的消费者用到的域名始终是taobao,消费者不需要关心具体自己访问的这个页面是运行在哪一台服务器上面的。

如果使用了负载均衡技术,那Session储存在什么地方就显得尤为重要了。因为,即使是不同的进程要共享同一台服务器的内存都非常困难,更不要说不同的服务器读取其中某一台服务器上某个进程的内存了。

如果使用Redis来存储Session,那么只要每一台服务器都能访问Redis,那共享Session的问题就不再是问题了。

3.本实例的Session储存机制

本实例使用Redis的哈希表来存储Session。当用户注册账号,或者登录成功以后,网站会使用下面一个函数生成Session信息:

代码11-1 生成Session与SessionID

其中,主要代码说明如下。

● 第2、3行:设置Session的过期时间为“距离现在30天”。

● 第4~6行:在Session中储存的信息包括用户的ID、用户名和过期时间对应的时间戳。

● 第7行:生成SessionID,这里使用的是UUID。

其中,Session 里面具体保存什么信息,可以根据项目的要求自己确定。SessionID 只要保证不重复即可,使用什么方式生成都没有问题。

网站使用这个函数生成 Session 和 SessionID 以后,会把它们保存到 Redis 的哈希表中, SessionID作为字段名,Session转换为JSON字符串以后作为值。同时,SessionID还会被添加到用户浏览器的Cookie中。

4.本实例的Session查询原理

当用户访问了一个需要登录的页面以后,网站会首先从请求的 Cookie 中获得 SessionID,然后使用这个SessionID去Redis中查询Session。查询会有4种情况。

● Cookie中没有SessionID,说明用户没有登录,则转到登录页面。

● Cookie中有SessionID,但是Redis的哈希表中找不到这个SessionID,也认为用户没有登录,则转到登录页面。

● 在Redis中根据SessionID成功找到Session,但是比对发现这个Session的expire_time小于现在的时间,说明这个Session已经过期了,则需要让用户重新登录。

● 找到Session并且它没有过期,则可以正常使用。

当找到正常可用的Session后,网站就会从Session中读取出用户名,将其显示在网页的右上角。由于用户名是不重复的,那么如果一个问题的提问者的名字和Session中的用户名是一样的,则说明这个问题就是当前这个用户提的。于是就给他打开修改问题的功能。回答也是一样的原理。



11.3.2 保存与读取用户信息


在用户注册时,需要保存用户信息;在用户登录时,需要读取用户信息。操作 MongoDB保存和读取用户信息的方法如下:

代码11-2 保存用户信息与读取用户信息

其中,主要代码说明如下。

● 第2行代码:记录当前时间,并转化为“yyyy-mm-dd HH:MM:SS”格式。

● 第4行代码:向MongoDB中插入数据,同时获取被插入数据的ObjectId。

这是常规的MongoDB读写操作。

提示:

save_user_info方法传入的password_hash参数是经过不可逆加密的密码。因为直接把用户的密码保存在网站数据库是非常没有职业道德也没有安全意识的行为,一旦发生数据泄露将会导致非常严重的灾难。



11.3.3 更新问题和回答


更新问题和回答,涉及的是常规的MongoDB更新操作,代码如下:

代码11-3 更新问题和更新答案



11.3.4 检查用户名是否已经注册


在用户注册时,需要检查用户名是否已经被注册过。对于数据量不大的情况,可以使用Redis的集合:

代码11-4 判断用户名是否已经注册

其中,第2行代码使用的Redis Key为qa_system:user:duplicate。注意,这里的冒号仅仅是普通的
m.qiduwx.com提示您,本章没有阅读完,点击下一页进入下一页阅读!

上一章 章节列表 下一章