前面的章节我们提到过,http 协议有缺点,其中一个就是无状态,简单来说就像一个人记性不好,那就得借助一些外在的东西来弥补这个缺陷。

先看下面的例子。

一般情况下,无状态协议也没有什么问题,比如A浏览新闻内容,B浏览新闻内容,只要服务器把新闻内容返回给浏览器就行了。
image.png

但是在特殊的情况下,如用户A登录购物网站去进行购买商品,那这个登录信息就需要保存下来,后续用户进行商品浏览、添加购物车等行为时,服务器可以知道是哪个用户进行的操作。而 http 因为是无状态的,前一个请求跟后一个请求是没有任何关联的,也就是说当我们输入账号密码进行了一次登录请求之后,后面再进行添加购物车的请求就得再输入一次账号密码,然后进行购物又得再输入账号密码,那这肯定是不现实的。

那怎么解决这个问题呢?而 http 的状态管理(会话机制)就是用来弥补 http 无状态的缺点。两种用于保存 http 状态的技术就应运而生了。

这两种手段怎么来的呢?下面先讲一个小故事。
老板开了一个咖啡馆,为了挣钱,就搞了个活动,活动就是满10杯送一杯。那么怎么让大家记住这个次数就是一个问题。
方案一:老板记住来过的所有人,并且记住他们每个人的次数,但老板和 http 协议一样,记性不太好,记忆的时长也比较短,那这个方案是肯定不行的;
方案二:老板是个程序员,自己搞了个小系统,客户第一次点咖啡就在系统上建个账号,每次点咖啡就在这个计数器上加1,但是这时客户不满意了,这个系统只要老板存着,客户没凭没据的,老板说几次就是几次,那这个方案也不行;
方案三:客户第一次来的时候,就给客户发一个小卡片,没点一次就在这个卡片上盖一个印,盖满10次就回收,觉得这个方式还不错就推行了,但是一段时间后,老板发现亏本了;后来老板发现有些人总来白喝咖啡,出去才发现咖啡馆不远处的小角落里有个刻印的人,这人刻的印和店里的一模一样,所以很多人喝完一杯就去刻印,印完就回来换咖啡,那这也不太行;

在这里,老板只在系统里计数这是只在商家,给客户发小卡片这是只在客户。所以要做一个设计就是不光客户端有,服务器端也要有,那就发行一个卡,卡在客户手里,数据在系统里,后面客人的卡和系统的数据一对,没问题,那就可以发咖啡了。

在这样一个例子里,老板就是服务器端,客户就是客户端,老板通过这种会员卡的方式大大减少了记不住的问题,就像 session 和 cookie,cookie 是在客户端的,session 是在服务器端的,然后减少了 http 无状态带来的问题。所以我们将 sesssion 和 cookie 称为回话跟踪技术。

Cookie

那就先从客户端说起,了解什么是 cookie。

Cookie 实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器颁发一个 Cookie。无论是谁访问该页面都给它颁发一个“通行证”,这样服务器就能通过这个“通行证”确认对方的身份了。

客户端浏览器会把 Cookie 保存起来。当浏览器再请求该网站时,浏览器把请求的网站连同该 Cookie 一同提交给服务器,服务器检查该 Cookie,以此来辨认用户状态。

image.png

Cookie工作原理
**
image.png

当客户端第一次访问网站时,服务器就通过 set-cookie 这样一个响应头来把 cookie 发送给客户端,把 cookie 储存到本地中(浏览器的存储或者其他地方),当下次再发送请求的时候会在请求头上带上这个 cookie 请求头,服务器端接收到这个 cookie,检测该 cookie 对应的用户是否真的存在于我们服务器上,如果就返回相应的用户信息给客户端。

如下图是一个示例。请求CSDN文章内容时,服务端首先会在cookie中设置一些id信息。
image.png
客户端发送的请求,请求头中的cookie带上了一些id信息。image.png
同时,为了安全起见,cookie的存储是有要求的。ID存放在对应的服务器的域名下,不能跨域访问

Session

web 应用程序中经常还使用另一种记录客户端状态的机制—Session。session 是由服务端生成的,保存在服务器上。客户端第一次浏览器访问服务器时,服务器把客户端信息以某种形式记录在服务器上。客户端浏览器再次访问时就只需要从该 Session 中查找该客户端的状态就可以了。

image.png

如果说 cookie 是通过检测客户身上是否有“通行证”的话,session 就是通过查询系统上的客户明细表来确认客户信息。

保存Session ID的方式

URL重写

刚刚我们说了通过 cookie 来存储 sessionId 是最常用的方法,目前 90% 以上的网站都支持这种方式,但是我们客户是可以人为地把客户端浏览器的 cookie 给禁用掉,那是不是一旦 cookie 被禁止了,sessionId 的机制就没办法再用了呢?
其实还有一种经常被使用的技术叫做 URL重写
**
URL重写就是直接将sesssionId的信息直接附加到 URL 路径的后面,作为这个 url 路径的附加信息,如下图1;另一种是作为查询字符串(参数)的形式放到 URL 后面,如下图2;
image.pngimage.png

隐藏表单
**
这种方式就是服务端会自动修改表单,添加一个隐藏字段,里面保存了 sessionId,当提交表单信息时,能把这个 sessionId 传递给服务器端。

Session 有效期

与 cookie 一样,session 也是有有效期的,但不同的是 cookie 的有效时间一般都比较久,session 由于有越来越多的用户来访问服务器,因此 session 也会越来越多,为了防止内存溢出,服务器会把长时间不活跃的 session 从内存中删除,这个时间就是 session 的超时时间,如果超过一定的时间没有访问服务器,服务器就会把这个 session 删除掉;
除了上面的被动失效,还有用户主动进行用户注销,退出登录等,这是通过服务器程序调用接口使得 session 失效。

Cookie 与 Session区别

  • 存放位置不同:cookie 存储在客户端,session 存储在服务器端;
  • 安全性不同:cookie 存在浏览器里面,对客户端是可见的,客户端的一些程序有可能会窥探或者修改 cookie 中的内容,session 存在服务器里面,对客户端时透明的,不存在信息泄露的风险;所以对于一些用户隐私的信息一般不能往 cookie 里写;
  • 有效期的不同:通过设置浏览器的 cookie 的过期时间属性,cookie 就可以在浏览器保存很长时间,但 session 不行,服务器会定时地清理 sessionId,避免出现过大的压力,并且 session 依赖于名为 sessionId 这样的 cookie,而 cookie 的 JSessionId 的过时时间默认是 -1,所以只要关闭了浏览器,这个 session 其实就失效了。

to be continue…