详解 Session 和 Cookie
前提
51 也有个文章跟我一样,是我自己投的稿哈
为什么要用Session和Cookie?
简单一句话,因为 Session 和 Cookie 可以记录用户状态信息
嘶..这到底啥意思呢?
背景一:动态网页的出现
什么是静态网页
- 含义:一个网页的内容是 HTML 代码编写的,文字、图片等内容均可通过HTML代码指定了
- 优势:加载速度快,编写简单
- 劣势:可维护性差,扩展性差,不能根据URL显示不同的内容;例如:在 URL 传入一个name参数想在网页上显示,静态网页是无法做到的
- 总结:弊大于利
动态网页的诞生
- 动态网页可以动态解析 URL 中参数的变化,关联数据库并动态呈现不同的页面内容,非常灵活多变
- 现在遇到的大多数网站都是动态网站,不再是一个简单的 HTML 页面,可能由 JSP、PHP、Python 等语言编写的,功能比静态网页强大和丰富太多
场景:一个需要登录的动态网站,在登录后需要保持登录状态,以便后续访问网站其他网页;那么我们要通过什么来保存这个登录态呢?
背景二:HTTP是无状态协议
HTTP无状态是指?
HTTP协议对事务处理是没有记忆能力,也就是说服务器不知道客户端是什么状态
这是什么意思呢?
- 当我们向服务器发送请求后,服务器解析处理请求,然后返回响应,服务器负责完成这个过程(也是一个事务)
- 而这个过程是独立的,服务器不会记录前后状态的变化,也就是缺少状态记录
无状态导致的后果?
- 意味着后续发出的请求需要处理前面请求的响应,则必须重传
- 这也导致需要额外传递一些前面的重复请求,才能获取后续响应
- 但为了保持前后状态,我们也不能将前面的请求全部重传一次,这太浪费资源了
- 就好像如果一个网站每次发出一个请求前都要先发出一次登录请求,这无疑大大增加了资源浪费程度
举栗子:百度
网站常常需要记录访问者的一些基本信息,例如:用户是否登录、用户登录名称、密码、用户在 Web 站点购物的方式或用户访问该站点的次数
举个例子,用户在没有登录 baidu 时,此时用户的身份是游客,baidu 首页的界面如下图所示:
当用户登录 baidu 页面后,此时用户的身份是已登录用户,可以看到页面的右上角显示了用户的名称,如下图所示
- 可以看出,baidu 服务端能够辨别用户的身份,根据用户是否登录显示不同的内容
- 如果用户的身份是游客,则显示登录
- 如果是已登录用户,则显示用户的名称
Seesion和Cookie的诞生
上图可以看出,Session 和 Cookie 在一个网站中各自发挥的作用
使用 Cookie 辨别用户的身份
- 网站为了辨别用户身份、进行会话跟踪需要把一些数据(例如:登录状态、用户名称)储存在用户本地终端上,这些数据被称为 Cookie
- 以登录 baidu 为例子,用户在没有登录 baidu 时,访问的网页 URL 是 https://www.baidu.com
- 在登录 baidu 后,访问的网页 URL 仍然是 https://www.baidu.com
- 访问的页面 URL 相同,但是这两次访问呈现的结果不相同,登录前没有显示用户名,登录后显示了用户名
那服务端是怎么区分两个请求呢?
- 用户登录 baidu
- baidu 服务端会生成一个用户 ID
- baidu 服务端将这个用户 ID 发送给浏览器
- 浏览器收到这个用户 ID 后,会将这个用户 ID 保存在用户本地终端
- 浏览器再次访问 baidu 站点时,浏览器会将保存在本地的用户 ID 发给 baidu 服务端
- 服务端收到浏览器发送的用户 ID 后,就知道此次请求来自于一个已登录的用户
以上交互过程中,保存在客户端的用户ID 就是 Cookie
实际场景
- 当我们登录之后,服务端就会创建一个属于当前用户的 Session,里面保存的就是当前用户的信息;
- 然后浏览器会根据服务器的响应头中 Set-Cookie 字段生成相关 Cookie,相当于一个用户凭证
- 只需要在下次请求时携带这些 Cookie,服务器就能通过 Cookie 来判断用户是否是登录状态,然后返回对应的响应
不好理解?继续往下看!
生动形象理解Cookie和Session的关系
- Session 是保存在服务器端,Cookie 是保存在客户端
- 每次用户访问网站的时候,相当于去串门
- 用户带着 cookie 去服务器家,当当当敲门
- 服务器问是谁啊
- 用户:是我(cookie)啊
- 服务器:让我来确认一下(session确认)
- 服务器确认完毕后,放用户进门
实际网站登录请求的响应头
- 这是一个网站登录之后返回的响应头,可以看到服务器要求浏览器设置的 Cookies 有好几个;这就是 Cookies 的来源,而 token 一般会作为用户的唯一凭证【登录成功,响应头set-cookies,浏览器设置Cookies】
- 当浏览器下一次再请求该网站时,浏览器会把这些Cookies放到请求头一起提交到服务器;而Cookies携带了SessionID信息(x-token)【再次请求,带上 cookies,包含 SessionID】
- 服务器通过 SessionID 即可找到对应的用户 Session 信息,然后判断该用户的登录状态【服务器根据 SessionID 获取用户信息】
- 如果 Session 中某些设置登录状态的变量是有效期内的,证明用户处于登录状态【Session 有效,用户已登录】
- 此时服务器就会返回需要登录之后才可以查看的网页内容,浏览器再进行解析便可以看到了【返回请求响应内容】
- 当 Cookie 无效或者 Session 已过期后,我们再访问网站就需要重新登录了【Cookie 无效,Session 过期,需要再次登录】
使用 Cookie、Session 最简单的流程图
Session和Cookie在登录功能上的协同关系
Session
- 是在服务端保存的一个数据结构
- 用来存储用户的信息(比如登录状态、用户名称)
- Session 数据可以保存在内存(比如 Redis)、文件或数据库中
- Session 有一个唯一标识 SessionID,会对应一个用户
- 在服务端通过 SessionID 会找到特定的一个用户数据
小栗子
- 假设有 2 个用户:用户 A 和用户 B;
- 在服务端存在 2 个 Session,用于存储用户 A 和用户 B 的数据
在服务端通过 SessionID 查找 Session 的过程如下
- 每一个 Session 有一个唯一标识,用户A 的 SessionID 为0,用户B 的 SessionID 为1
- 用户访问网站时,会把自己的 SessionID 作为 Cookie 发送给服务端
- 服务端根据请求中的 SessionID 来查找对应的 Session
实际场景
- 在Web中,Session对象用来存储特定用户 Session 所需的属性和配置信息,这样用户在应用程序的Web页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户 Session 中存在下去
- 当用户请求网页时,该用户还没有 Session,则Web服务器将自动创建一个 Session 对象
- 当 Session 过期或被放弃后,服务器将终止该 Session
Cookie
某些网站为了辨别用户身份,进行 Session 跟踪而存储在用户本地终端上的数据
会话Cookie和持久Cookie
会话Cookie
可以将打开浏览器-关闭浏览器理解成一个会话,会话Cookie的有效期仅在浏览器打开期间;而会话Cookie是存在浏览器内存里的
实际场景:涉及钱,涉及利益、机密内容的网站一般都是会话Cookie,如企业邮箱等
持久Cookie
持久Cookie是存在客户端本地硬盘中,不受浏览器关闭影响,下次再次访问该网站时还能继续使用,用于长久保持用户登录状态
实际场景:可以勾选【自动登录】、【30天内自动登录】的网站用的就是持久Cookie
持久Cookie发出请求时,客户端与服务器之间的时序图
浏览器中看Cookie
- Name:Cookie 的名称。Cookie 一旦创建,名称便不可更改
- Value:Cookie 的值。如果值为 Unicode 字符,需要为字符编码。如果值为二进制数据,则需要使用 BASE64 编码。
- Domain:Cookie注入的域名,如.baidu.com下的Cookie,只要Host以.baidu.com结尾的域名都能访问该Cookie
- Path:允许使用该Cookie的路径,一般都为 /
- Expires/Max-Age:Cookie失效时间,若没有指定失效时间则默认当浏览器关闭时Cookie失效
- Size:Cookie大小
- HttpOnly:若True,则不允许脚本来访问该Cookie(如:JS)
- Secure:Cookie是否仅被使用安全协议传输,默认为False
敲重点的知识点
“只要关闭浏览器,Session 就消失了” —— 错!
实际场景:去健身房办理的会员卡,除非你自己要求销卡,不然店家不会随意销掉你的卡
所以,对于 Session 也是一样的,登录的时候服务器帮你生成了一个 Session,是不会轻易删除你的 Session,除非你自己提出要删除 或 Session有效期过了;而一般我们会通过【退出】来删除触发服务器删除 Session
当我们关闭浏览器时,浏览器是不会通知服务器说它要关闭,所以服务器根本不知道浏览器已关闭,造成这样的误解全都是因为:
- 一般情况下,网站都会用 Cookie 来保存 SessionID 信息的
- 当你的 Cookie 是会话 Cookie 时,关闭浏览器 Cookie 就会消失
- 再次打开网站也找不回之前的那个 Cookie 对应的 SessionID
- 所以无法通过原来的 SessionID 在服务器查找对应用户的登录状态,只能重新登录生成新的 Cookie 来记录新的 SessionID
如何解决?
就是将 Cookie 设置为持久 Cookie,当你关闭浏览器再打开网站时,还是能从本地读取到 Cookie,从而获取到原来的 SessionID,以此来保持登录状态
另外
而恰恰因为关闭浏览器并不会让服务器主动删除 Session,为了避免服务器的资源浪费,一般服务器都会为每个 Session 设置一个失效时间,当 Session 的时间超过失效时间时,服务器会自动删除 Session