登陆

面试题:说说你对Session的了解?

admin 2019-08-23 182人围观 ,发现0个评论
作者:千里明月 
来历:https://my.oschina.net/mingyuelab/blog/2986928

# 简介


session(会话),其实是一个简单让人误解的词。它总跟web体系的会话挂钩,运用session,javaweb项目完成了登录状况的操控。坊间撒播,封闭浏览器,就是封闭了web体系的会话。


其实浏览器关于会话有自己的界说,而web体系关于会话也有自己的界说。在tomcat中,session通常是指完成了HttpSession接口的完成类。并且不存在封闭浏览器就会封闭tomcat的HttpSession这种状况。


session自身并不难,假如仅仅做登录校验之类的功用,并不需要深化了解,但难的是session和cookie的结合运用,在不同状况下浏览器对cookie的操控行为所涉及到的许多细节,我搜寻了许多材料,查看过tomcat源码,亦是没有找到全面的概述。


当然我并未看过、也不知道去哪里看比较全面的关于浏览器对cookie的操控材料,假如有知道的大神,还望留言链接。本文标题,之所以说是评论,而不是了解或许介绍,因为我自己也卡在了某个点上,因为时刻联络,我不能花太多时刻去研讨,但又不忍心就此抛弃,所以先记录下来,日后有时机再研讨,这期间如有大神点拨,或许能让我恍然大悟。


# Session实质


我用的是javaweb项目,因而这儿的session特指HttpSession。先来看下tomcat源码中对session的规划,在org.apache.catalina.session包下,有如下规划。



平常所用到的HttpSession的完成类就是这个standardSession。可是所获取的HttpSession实例确是外观类StandardSessionFacade,其屏蔽了许多办法,但也增强了安全性。


HttpSession供给了一些办法,来操控session或许获取session的状况,如获取session的id,获取session的创立时刻,设置session的attribute,使session失效等。值得一提的是session的attribute其实是一个线程安全的hashMap。


/**
* The collection of user data attributes associated with this Session.
*/
protected ConcurrentMap attributes = new ConcurrentHashMap<>();


可是,创立session、依据id获取session的办法并不在这儿,而是在一个办理器中,其规划如下。


ManagerBase是完成了Manager接口的抽象类,完成了办理session的功用。其完成子类PersistentManagerBase拓宽了将session耐久化的功用。可是这儿不需要讲到其子类。


看ManagerBase中的一段代码。


 /**
* The se面试题:说说你对Session的了解?t of currently active Sessions for this Manager, keyed by
* session identifier.
*/
protected Map sessions = new ConcurrentHashMap<>();


由此可知,所谓的session,其实就是一个用线程安全的hashMap存储起来的完成了Session接口的standardSession目标,在hashmap中以其id为key,自身为value。


再看获取session的办法,一望而知。


 @Override
public Session findSession(String id) throws IOException {
if (id == null) {
面试题:说说你对Session的了解?return null;
}
return sessions.get(id);
}


最重要的是看其createSession办法。

这个办法是在什么时候调用的呢?当浏览器拜访体系时,request会解析恳求中带着的jssesionid,用它去找到存在于运用中的session,可是假如没有找到,那么就会调用session的创立办法,并且生成一个新的jssessionid,回来session。


总而言之,session是存在于线程安全的map中的值,能够经过id找到,也能够运用invalidate办法毁掉,但绝不会是浏览器封闭,就能对它进行毁掉的。


# Cookie 简介


提到session,那么cookie是不得不说的。至于cookie是什么,我就不多说了,咱们都懂。直接看其内容吧。



这是一次http恳求中(http://localhost:8080/test1),包含的恳求和呼应信息,是对一个体系的初度拜访,用的是谷歌浏览器。


恳求头中,包含的Cookie信息,并没有上文提到的jsessionid, 那是因为这是对体系的初度拜访,体系还没生成session。可是拜访之后,体系就会生成一个session,并且,会在呼应流中设置呼应头Set-Cookie,其值为JESSIONID=xxx。这样浏览器对localhost:8080和cookie的联络就有了回忆,浏览器会将其存储起来,可在调试东西中看到。



那么再次拜访http://localhost:8080/test1, 浏览器会自动在恳求头添加包含jsession的cookie信息。



体系依据这个jsessionid找到session,也就不会在呼应头中添加Set-Cookie信息。


这儿说一下cookie中的两个重要特点。


  • domain表明的是cookie地点的域,默以为恳求的地址,如网址为www.test.com/test/test.aspx,那么domain默以为www.test.com。而跨域拜访,如域A为t1.test.com,域B为t2.test.com,那么在域A出产一个令域A和域B都能拜访的cookie就要将该cookie的domain设置为.test.com;假如要在域A出产一个令域A不能拜访而域B能拜访的cookie就要将该cookie的domain设置为t2.test.com。
  • path表明cookie地点的目录,默以为/,就是根目录。在同一个服务器上有目录如下:/test/,/test/cd/,/test/dd/,现设一个cookie1的path为/test/,cookie2的path为/test/cd/,那么te面试题:说说你对Session的了解?st下的一切页面都能够拜访到cookie1,而/test/和/test/dd/的子页面不能拜访cookie2。这是因为cookie能让其path途径下的页面拜访。


# 疑点


下面,就该说下我的疑点了。


状况1


可是当我在8081的一个办法中,重定向到8080的一个途径时,发现了古怪的现象。


8081体系的办法如下。


 @GetMapping("/test")
public void get1(HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
String id = session.getId();
System.out.println(id);
response.sendRedirect("http://localhost:8080/test1");
}


8080体系的被重定向途径如下。


 @GetMapping("/test1")
public void get11(HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
String id = session.getId();
System.out.println(id);
}


1、初度拜访localhost:8081/test 得到两次恳求的信息,一次是重定向的,一次是8080的。


这阐明对8081体系的初度拜访,是没有发送jsessionid信息的,而8081体系生成了一个id为CAAB6AED34716A0394705BDE8CAC0042的session并设置到了呼应头,再次拜访8081时理应会带上这么一个id。

2、

这个对8080体系的恳求中带有jsessionid为CAAB6AED34716A0394705BDE8CAC0042的cookie信息,要知道,咱们对8080的拜访也是初度的,那么为什么会带上jsessionid呢?并且这个jsessionid显着是在8081体系中生成并设置到呼应头的的jsessionid。这个现象我用谷歌和edge浏览器别离尝试过,都是这样。那么是不是阐明,浏览器把这个重定向到localhost:8080的恳求当成是同域的恳求了 。


暂时放下这个疑问,持续往下验证。因为这个恳求是对8080的体系的拜访,如东天气预报因为是初度拜访,体系底子没有id为CAAB6AED34716A0394705BDE8CAC0042的session,因而只好生成一个新的session,在呼应头中添加Set-Cookie。


3、

再次拜访localhost:8081/test,这时依据上文说的,“再次拜访8081时理应会带上这么一个id”,也就是在cookie中带上JSESSION=CAAB6AED34716A0394705BDE8CAC0042, 可是,我发现它带的却是在体系8080中生成的BA0D2C939ADEC087C0A5F0C9B3354891 !!!


这就导致了8081找不到session又再次生成了一个新的session,循环往复,每次对8081的拜访都会发作新的session。而这状况,我觉得很显着,是浏览器把对8081的拜访当成是于8080同源的了。


根据此推论,我模拟了另一种试验状况,去掉重定向的功用:


状况2


在本地开两个web服务,端口别离是8080,8081。


localhost:8081/test


 @GetMapping("/test")
public void get1(HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
String id = session.getId();
System.out.println(id);
}


localhost:8080/test1


 @GetMapping("/test1")
public void get11(HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
String id = session.getId();
System.out.println(id);
}


1、第一次拜访8081/test


没有cookie,服务器设置set-cookie,正常。


2、第2次拜访8081/test



cookie与前次的set-cookie共同,正常。


3、第一次拜访8080/test1



浏览器把8081/test的cookie发过去了。8080的服务器找不到这个jsessionid,又从头设置了jsessionid,比及再次拜访8081/test时,咱们也能猜到会发作什么了吧。


# 推论


至此,我大胆推论,浏览器会对同一ip不同端口的服务拜访确定是能够进行cookie同享的,两个cookie的domain是共同的。而这种cookie的截图也必定程度上印证了我的主意。

cookie的domain好像只确定域名,无关端口。

可是依据浏览器的同源战略,同域名不同端口的拜访也应该是跨域的啊。除非浏览器的域跟cookie的domain在概念上是有差异的,关于这点,我没找到切当的官方材料,但网上大神是这么说的。


解决方案


根据上面的未查阅官方材料而做出的不谨慎的推论,我想,只需完全避免同域的状况就能够避开这个问题。所以我把8081和8080体系别离布置在两个机器上。因为不同ip,这样无论如何,两个cookie都不会是同domain的了。公然,结果是没有问题的。


缺乏


尽管这个解决方案避开了同域的问题,可是没有彻底解决,究竟同域的体系相互之间的拜访也是有必要的,为此希望能取得更多的主张或许材料,弥补这方面常识的缺乏,让我彻底解决这个问题。




这儿,东哥来做个总结吧,文中的作者卡在了同源战略和跨域的问题,本文描绘的的问题是归于跨域的问题。

同源指的是协议、域名、端口都相同(可经过题图来了解此概念)。浏览器之所以要拟定同源战略,其意图就是避免页面加载来历不明的脚本,而被黑客操作。

而跨域指的是域名不同,跟端口没有联络。比方常用的JSONP技能,就是运用了