web 会话机制之 session cookie 详解( 四 )


  • 每一个HttpSession有一个唯一的标识SessionID,只要同一次打开的浏览器通过request获取到session都是同一个 。
  • WEB容器默认的是用Cookie机制保存SessionID到客户端,并将此Cookie设置为关闭浏览器失效,Cookie名称为:JSESSIONID
  • 每次请求通过读取Cookie中的SessionID获取相对应的Session会话
  • HttpSession的数据保存在服务器端,所以不要保存数据量耗资源很大的数据资源,必要时可以将属性移除或者设置为失效
  • HttpSession可以通过 setMaxInactiveInterval() 设置失效时间(秒)或者在 web.xml 中配置
<session-config>    <!--单位:分钟-->    <session-timeout>30</session-timeout></session-config>session 的创建时机一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用 HttpServletRequest.getSession(true) 这样的语句时才被创建 。
Session 何时被删除综合前面的讨论,session 在下列情况下被删除
  1. 程序调用 HttpSession.invalidate();
  2. 距离上一次收到客户端发送的 session id时 间间隔超过了session的超时设置;
  3. 服务器进程被停止(非持久session)
JSESSIONID 的创建与获取我们在 session 创建的时候,也就是第一次调用 HttpServletRequest.getSession(true) 时,会给客户端分配一个 JSESSIONID 用于唯一标识这个用户 。
这个信息会被写回到客户端的 cookie 中,并且后续的请求都会携带 。
比如我测试时的 JSESSIONID:
Cookie: JSESSIONID=8AE65FE9AEB0AA6053FADF9ED7AEE544可以发现实际上 JSESSIONID 是非常依赖客户端 cookie 的,那么问题来了,如果用户禁用了 cookie 怎么办?
客户端禁用 cookiecookie 是用户自己的口袋,如果用户有一天把口袋全部封死也是有可能的 。
如果客户端禁用了 cookie,一般有两种解决方案 。
隐藏域我们将 JSESSIONID 的值传入到页面中,放入一个隐藏的 input 框中,每次请求带上这个参数 。
<form name="testform" action="/xxx">   <input type="hidden" name="jsessionid" value=https://www.isolves.com/it/cxkf/bk/2021-01-07/"8AE65FE9AEB0AA6053FADF9ED7AEE544"/>   后端通过 req.getParameter("jsessionid") 的方式获取到这个 jsessionid 信息 。
URL 重写URL地址重写的原理是将该用户Session的id信息重写到URL地址中 。服务器能够解析重写后的URL获取Session的id 。
这样即使客户端不支持Cookie,也可以使用Session来记录用户状态 。
encodeURL() 方法在使用时,会首先判断Session是否启用,如果未启用,直接返回url 。
然后判断客户端是否启用Cookie,如果未启用,则将参数url中加入SessionID信息,然后返回修改的URL;如果启用,直接返回参数url 。
就像老马前面代码写的一样:
// 后端会根据页面是否禁用 cookie,选择是否将 sessionId 放在 url 后面String url = resp.encodeURL("/session/get");out.println("<a href=https://www.isolves.com/it/cxkf/bk/2021-01-07/'"+url+"'>获取 session 信息");如果我们禁用 cookie,链接的地址就会变成:
http://localhost:8080/session/get;jsessionid=3E2EEB9840F2566EDB3085BA392AE6CB;jsessionid=3E2EEB9840F2566EDB3085BA392AE6CB 这个是 encodeURL 自己加上去的,这样我们就可以像原来一样处理 session id 了 。
连锁店的机遇与挑战当目前为止,你作为一家店的老板已经可以轻松的掌握客户的信息了 。
哪怕用户把自己的口袋封死 。
随着你的生意越来越好,你的店从一家门面,变成了多家连锁店 。
新的问题又来了,一个用户去了其中的一家,当到另外一家店面的时候,如何得到用户对应的信息呢?
连锁店
这个就涉及到分布式系统的 session 共享问题 。
其实解决问题的思路也是从两个角度出发:
(1)用户的角度
在用户的口袋中放着验证信息 。
不过需要考虑信息被恶意修改等,这方面 JWT 做的比较优秀 。
可以参考:
分布式系统 session 共享解决方案 JWT 实战笔记
(2)服务者的角度
我们作为连锁店,只需要把各个店里的商户信息共享即可 。
至于共享到哪里,可以是 redis 也可以是数据库 。
这方面 spring session 设计的比较优秀,可以参考:
springboot整合redis实现分布式session


推荐阅读