文章目录
导读
在Web面试的时候,后台一定要清楚Session的工作原理,因为总有一些数据需要从后台传入前端。而在说Session的时候,不可避免地会谈到Cookies。本篇将详细阐述二者的区别。
概念
TCP/IP
网络协议
根据计算机网络原理,双方在通信时往往会互相发送报文,也就是把数据处理成了多个压缩包逐个发送。而在这个过程中,双方会建立一个虚拟连接通道。你问我为什么不是物理的?因为物理连接是一开始就存在的。如果是有线连接,物理连接就是网线;如果是无线连接,空气也能算介质。
那么,这个虚拟连接什么时候开始什么时候结束呢?
1、当我们要发送数据包前,快递员会先跟他提个醒:“快递到了,签收一下”
2、对面听到了之后回应:“好嘞”,然后把门打开了
3、快递员听到了回应之后,虚拟连接就成立了,搬运也就开始了
这就是我们俗称“三次握手”。
最后搬运完了之后,开始执行同样的操作。
1、快递员这边提个醒:“全部搬完了!”
2、对面听到了之后回应:“好嘞”,然后把钱递了出去
3、快递员收到钱之后,清点了一下,喊一声:“收齐啦!谢谢!”(没收齐是不会进入结束阶段的)
4、对面听到了,直接“砰”地就把门关上了,虚拟连接断开
你也可以叫他“四次握手”,也有人叫他“四次挥手”,这都无所谓了。
会话
会话在计算机术语中是指一个终端用用户与交互系统进行通讯的过程。“三次握手”建立了一个会话,“四次挥手”关闭了一个会话。例如,从你登录求职网一直到退出账号这整个过程都是会话。(摘自百度百科【会话】)
我们一般所说的“会话”,其实全称是“HTTP会话”。
HTTP
网络协议
只要你访问了互联网,网址栏永远会显示http://
或者https://
,这就是HTTP
协议的作用,也就是客户端和服务端之间的相互通信。但是HTTP
是无状态协议,也就是说不管你去哪访问,服务器永远不会管你先前干了什么,这也就是为什么好好的填了在线简历一刷新全都没了。这无疑是非常恐怖的。但是不用担心,我们有Session和Cookie。
Session
和Cookie
Session运行在服务端,当我们在连接中接入steam的时候,你就有了唯一一个SessionID
,这样服务器就确认了是你购买了这款游戏。与此同时,运行在客户端的Cookie
就帮我们保存了一小段的信息,一般是保存在内存中,用来记录各种各样的信息。正因如此,我们能免认证直接登录就是因为这段Cookie
在会话结束后存在了硬盘中,在有效时间内再次访问就会使用这段Cookie
;而一些做的并不是很好的网站却没有这个功能,直接关掉浏览器,甚至是关掉网页Cookie
就消失了,在登录和登出之间反复横跳。
你可能会怀疑:如果一个人登录修改了Session
,第二个人登进去会不会把第一个人顶出去?
Session
的工作原理
服务器系统会为每一个会话维护一个Session
,不同的会话对应不同的Session
。下面会详细解释为什么系统对每一个会话使用并一直保持使用完全不同的Session
来处理不同的会话。
写入Session
列表
这也是整个会话管理的第一步。
服务器对当前应用中的Session是以Map
的形式进行管理的,这个Map成为Session列表。我们知道,Map是以**键值对(key-value
)**的形式存储的,所以最终将会是一个多行两列的表格,每一行代表一个键值对。而Session
里面都是些什么啊?用表格表示的话就是这样:
key | value |
---|---|
D329C89C88DEC2189888FDF365961A87 | org.apache.catalina.session.StandardSessionFacade@1878aab4 |
9C7B848D2CCF19DC00B80218BC181838 | org.apache.catalina.session.StandardSessionFacade@78dded51 |
(以上数据均为举例,并不是真实数据)
左边的key
为32位随机串,是根据某种算法生成的字符串,被称为JSessionID
,也就是Java
类型的Session
对象的ID
值。右边的value
值就是HttpSession
对象的引用,存放在服务器的堆内存中。
当用户第一次提交请求的时候,服务端的Servlet执行到request.getSession()
方法后,会自动生成一个Map.Entity
对象,也就是键值对对象。一定要明确写明调用了getSession方法,因为只有在这种情况下服务端才会生成Session
服务器生成并发送Cookie
客户端
在服务器写入Session
列表后,系统还自动将JSessionID
以Cookie的形式保存在响应报头中,并随着这个报头,传送给客户端。
客户端接受并发送Cookie
到服务器
客户端接收到JSessionID
后,将这个存在浏览器缓存中。只要浏览器不关闭,Cookie
就不会消失。每次请求的时候,缓存中的Cookie
就会被封装到响应报头中发送到服务器。
服务器接收Cookie
并在表中查找发送的JSessionID
服务端从请求中读取到客户端发送回来的Cookie
,并根据Cookie
中的JSessionID
的值,在Map
中查找相应的key
所对应的value
,即Session
对象。然后,服务器才可以对Session对象中的对应属性进行读写操作。
这一整套流程像极了银行卡的办理和使用。
-
你到了银行,请求办一张卡
-
通过银行的某种随机算法,银行给了你一个随机的字符串,这就变成了你的唯一标识了
-
银行只给了你一张卡,卡上有你的唯一标识
-
你以后就可以拿着卡去找银行存取了。同样的,银行就通过你银行卡上的唯一标识来查找你的真实数据,然后修改
Session
的线程安全问题
虽然说银行能够对每一个客户的业务处理独立进行,线程安全问题可以在一定程度上得到保证。但是开发中Session多少还是有一定的线程安全问题。这一部分由于涉及源码,将会单独拉出来一个板块进行讲解。请移步:Session
的线程安全问题
附:Cookie
被禁后的Session
运行流程
上面我们讲了,Session
的运行少不了Cookie
,在一定程度上说,Cookie
就是维持两边通信的基础。
但是别忘了,IE
是可以禁用Cookie
的。这种情况怎么办?禁用了Cookie
之后,客户端中将不再保存服务端送来的JSessionID
,下一次请求将是全新的请求,服务器会分配全新的JSessionID
,用户已保存的信息也就不能通过正常访问方式访问了,最后随着失效时间的到来而消失。
细心的你似乎已经发现了,我说的是不能通过正常方式。非正常的访问方式是:你通过抓包抓住了JSessionID,然后使用同样的网址
+;
+JSessionID=
+记录下来的JSessionID
。这个时候你就能在请求的同时把原来的JSessionID强行送出去,然后服务器就知道了你的身份。
但是,这个身份不一定是你,而是能够使用抓包工具抓到包的任何人。更可怕的是,抓包工具就集成在浏览器中,也就是我们所熟知的F12开发者选项。
这也引出了另一个问题:会话到底是什么时候结束?
答案是:Session消失了会话才会结束。我们一开始就已经强调了,服务器会为每一个会话维护一个Session。这也是为什么电商平台往往要有退出按钮。
但是我们该怎么在Cookie被禁掉之后重新找到原来的数据呢?Servlet有重定向和非重定向方法。
重定向
// 先确定接口位置
String uri = request.getContextPath() + "/api";
// 解决Cookie禁用后重定向时Session的跟踪问题
uri = response.encodeRedirecrtURL(uri);
response.sendRedirect(uri);
这样不管是否禁止Cookie
就都能找到我的用户数据啦!简直不要太完美!
可现实是:你的JSessionID
明晃晃地挂在地址栏上。这可了不得,你把自己的位置都给暴露了,还不怕别人暗中狙你一枪?
非重定向
// 先确定接口
String uri = "api";
// 解决Cookie禁用后非重定向时Session的跟踪问题
uri = response.encodeURL(uri);
out.println("<a href='" + uri + "'>跳转</a>");
同样的,这样不管是否禁用Cookie
都可以访问到原有的JSessionID
。但是别忘了,a标签可是GET
请求啊!明明白白地打在地址栏上的啊!
以上,就是Session
的全部内容。实际上Session
还有非常多的细节问题,但是最重要的还是工作原理的部分。