本篇文章参考来自购买的 bravo1988 - 知乎 (zhihu.com)的java小册!!!
1.什么是Http协议
做javaWeb相关的都知道Http协议的规则是请求和响应的,请求-响应这种通信模式,即服务器不会主动搭理客户端,只是被动地响应客户端的请求。最重要的一个特性是无状态的,什么是无状态呢,就是每次请求对于服务器来说都是全新的请求,即使浏览器那边是同一个发出的,服务器是无法识别浏览器发出的请求是谁,是否之前请求过,所以也就导致了一个问题,既然是无状态的,那么我们登录购物网站,登录论坛,是如何确认到是我们的账号登录并操作的,这就是Cookie和Session作用所在。
2. 什么是会话机制(Session)
会话机制最主要的目的是帮助服务器记住客户端状态(标识用户,跟踪状态)。
有了会话机制,那么服务器就可以识别客户端/浏览器,就可以将同一个用户发出的请求归类在一起,例如,你淘宝购物车你添加了一些商品后,不可能重新打开淘宝后购物车中的商品变成你女朋友的添加的商品。
所以理解的重点就是:
- 首先明白http协议是无状态的,并且理解什么是无状态;
- 然后明白无状态的http协议有哪些不足,于是会话机制弥补了http协议因为无状态产生的缺陷;
会话机制的定义 :
是一种记录浏览器状态的机制。不同的是Cookie保存在浏览器中,Session保存在服务器中。
会话,指用户登录网站后的一系列动作,比如浏览商品添加到购物车并购买。会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定
注意:Session翻译过来就是会话机制,这种机制的实现在规则和代码层面又有两种类型分别叫做Cookie和Session
3. 如何定义一次会话
在计算机的世界中,会话又是什么?大家可能早就听过这句话:
从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,称为一次会话。
我们会有以下的疑问:
-
为什么浏览器关闭代表一次会话结束?
-
关闭时发生了什么操作导致会话结束?
-
为什么那个操作执行意味着会话结束?
归根揭底,我们只需要明白什么才能代表一次完整的会话!!!
一个会话可以帮助服务器断定一个客户端,那么反向推导得到的结论就是:当服务器无法断定客户端时,一次会话就结束了!
服务器什么情况下无法断定一个客户端?无非两种情况:
- 服务器识别不到session了(session失效)
- 客户端没有携带Cookie访问服务器(cookie失效)
又基于上面分析,可以总结出一次会话存在的基本原则:
- 双方共存(cookie与session同时存在)
4. 认识Cookie
Cookie实际上是一小段的文本信息。客户端第一次发出请求,请求服务器时,如果服务器需要记录该用户状态,就会使用response向客户端浏览器响应回一个Cookie。客户端会把Cookie保存起来,保存在浏览器的内存中。
疑问:是否客户端的第一次请求肯定会响应回一个cookie?
当浏览器再次请求该网站时,浏览器发出的请求中会携带着该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
其实Cookie可以分为两种:
- 会话Cookie (Session Cookie)
- 持久性Cookie (Persistent Cookie)
会话Cookie:
被保存在浏览器的内存中,当浏览器关闭时,内存被释放,内存中的Cookie自然也就烟消云散。这样太麻烦了,关闭浏览器引发Cookie消失,下次还要重新登录。能不能向客户端响应持久性Cookie呢?只要设置Cookie的持久化时间即可!查看对应的API可以设置。
对于每种不同的浏览器,不管是会话Cookie还是持久性Cookie,都是相对独立的,每家浏览器厂商会话Cookie(保存在浏览器内存中)和持久性Cookie(保存在电脑某个浏览器设定的文件夹中)存储的位置是不同的。所以,当你用Chrome登录京东,你再用IE打开京东时,仍旧要登录,因为你没有带去标识用户信息的Cookie(不论是会话Cookie还是持久性Cookie,IE都拿不到Chrome的)。
小结一下:
- 不设置MaxAge,默认响应会话Cookie(MaxAge<0),存在浏览器内存。Cookie随浏览器关闭而消失。
- 设置MaxAge>0,响应持久性Cookie,会存在电脑硬盘的特定文件夹下(浏览器自定义的),这样你关闭浏览器后在有效时间内请求服务器仍然可以是登录状态。
- 设置特定Cookie的MaxAge=0,则会删除已经存在客户端的此Cookie。
一般,响应给客户端的Cookie都是会话Cookie(不设置MaxAge),是存在浏览器内存中的。所以关闭浏览器后,内存中Cookie就消失了。Cookie消失,则下次请求服务器时,请求头中不存在代表用户信息的Cookie(唯一标识用户,表示其状态),那么浏览器就无法识别请求的用户。
根据我们上面反向推导的结论:当服务器无法断定客户端时,一次会话就结束了!
5. 认识Session
有了Cookie,似乎已经能解决问题,为什么还需要Session?原因似乎可以列举很多,有可能是出于安全性和传输效率的考虑。首先,Cookie是存在客户端的,如果保存了敏感信息,会被其他用户看到。其次,如果信息太多,可能影响传输效率。
相比较Cookie存在客户端,Session则是服务端的东西。其本质上类似于一个大Map,里面的内容,以键值对的形式存储。
每个用户访问服务器都会建立一个session,那服务器是怎么标识用户的唯一身份呢?事实上,用户与服务器建立连接的同时,服务器会自动为其分配一个SessionId。其实,只要你在服务器端创建了Session,即使不写addCookie("JSESSIONID", id)
,JSESSIONID仍会被作为Cookie返回。
要注意的是,Session有个默认最大不活动时间:30分钟(可在配置文件中修改数值)。也就是说,创建Session并返回JSESSIONID给客户端后,如果30分钟内你没有再次访问,即使你下次再带着JSESSIONID来,服务端也找不到对应ID的Session了,因为它已经被销毁。此时你必须重新登录。
我们需要知道:
1)SessionId的重要性:
什么东西可以让你每次请求都把SessionId自动带到服务器呢?显然就是cookie了,如果你想为用户建立一次会话,可以在用户授权成功时给他一个唯一的cookie。当一个用户提交了表单时,浏览器会将用户的SessionId自动附加在HTTP头信息中,其实也就是请求中带着Cookie(这是浏览器的自动功能,用户不会察觉到),当服务器处理完这个表单后,将结果返回给SessionId所对应的用户。试想,如果没有 SessionId,当有两个用户同时进行注册时,服务器怎样才能知道到底是哪个用户提交了哪个表单呢。
2)储存需要的信息。服务器通过SessionId作为key,读写到对应的value,这就达到了保持会话信息的目的。
6. session的序列化
所谓Session序列化,其实是一个默认行为。它存在的意义在于:比如现在有成千上万个用户在线,用户登录信息都在各自的Session中。当服务器不得不重启时,为了不让当前保存在服务器的Session丢失,服务器会将当前内存中的Session序列化到磁盘中,等重启完毕,又重新读取回内存。这些操作浏览器端用户根本感知不到,因为session还在,他不用重新登录。以Tomcat为例,服务器的Session都会被保存在work目录的对应项目下。关闭服务器时,当前内存中的session会被序列化在磁盘中,变成一个叫SESSIONS.ser的文件。
7. 钝化和活化
自从改用Session后,由于Session都存在服务器端,当在线用户过多时,会导致Session猛增,无形中加大了服务器的内存负担。于是,服务器有个机制:如果一个Session长时间无人访问,为了减少内存占用,会被钝化到磁盘上。也就是说,Session序列化不仅仅是服务器关闭时才发生,当一个Session长时间不活动,也是有可能被序列化到磁盘中。当该Session再次被访问时,才会被反序列化。这就是Session的钝化和活化。可以在Tomcat的conf目录下的context.xml中配置(对所有项目生效。
还有个问题需要解决:Session被序列化了,存在Session中的值怎么办?比如存在session中的是一个entity类的对象?
HttpSession session= request.getSession();
session.setAttribute("user", new User("eekk", 26));
此时Session中有一个User对象,那么User对象去哪了?答案是,User从内存中消失,无法随Session一起序列化到磁盘。如果希望Session中的对象也一起序列化到磁盘,该对象必须实现序列化接口。
总结:
-
我们需要知道cookie保存在客户端,session保存在服务端,cookie的产生是在服务端产生的,是浏览器第一次请求服务器,服务器响应给浏览器一个Cookie。
-
cookie只是一个通行证,但并不是安全的,任何安全的校验必须要在服务端上完成,cookie只是存在客户端上面的一个唯一标识它且由服务端定制的信息,本地可以改,但是不管怎么改,最后还是需要把它拿上发送给服务端进行匹配校验。
-
session和cookie的存储都存在时效性,这是很有必要的
-
不管是cookie还是session,都是建立在安全性的大前提下,session中不仅仅有cookie的信息,同时会有该用户的相关重要且安全的信息存储,所以session是在服务器的,而cookie只是服务器将一些不重要的信息拿出来丢给客户的存在,以备以后快速匹配校验用。
-
回到一个最值得思考的问题:
-
会话是如何建立起来的?
一次会话的建立就是浏览器第一次请求服务器,服务器响应回浏览器之前,会生成一个保存该浏览器用户信息的session,并放在浏览器,然后响应回浏览器的时候,将一个cookie交给浏览器,浏览器保存起来这个cookie,这样,就是建立以一次会话的开始。
-
什么是一次会话?是在什么时候结束的?
一次完整的会话就是在一次会话建立之后,在浏览器上的coolie和服务器上的session都还存在并且相互间可以验证对方的时候。
那么反推结束的时候就是浏览器上的coolie和服务器上的session只要有任何一方都失效,双方无法进行互相验证的时候,就代表会话结束了。
所以服务器能“知道”浏览器关了,是因为浏览器请求下次再来的时候,并没有带来上次给它的cookie。你无法证明你还是你。其实不一定是浏览器关了,也可能是清缓存了。总之,一次会话已经结束。这样理解:浏览器确实给服务器发了请求,但是请求中没有携带证明自己的身份证号(Cookie),所以服务器那边也就没法确认你是你自己。
-