有一个完整的认识。很多朋友还不清楚Cookie、Session、Token的区别。今天就带大家彻底了解它们。图片来自PexelsCookie夏洛:大叔,马冬梅家住322楼上吧?叔叔:什么是马?夏洛特:马冬梅。叔叔:没什么?夏洛特:马冬梅。叔叔:马怎么了?夏洛特:好的,先生,您应该先冷静下来。在了解这三个概念之前,我们需要了解HTTP是一种无状态的Web服务器。什么是无国籍?就像上面夏洛特烦恼中的经典对话一样,一个对话完成后,接下来的对话就完全未知了。谈话发生了什么。如果只是用来管理web服务器中的静态文件,那么不管对方是谁,直接从磁盘中读取文件发送出去即可。但是随着网络的不断发展,比如电子商务中的购物车,只有记住了用户的身份,才能进行接下来一系列的动作。所以在这一点上我们需要我们的无状态服务器记住一些东西。那么网络服务器是如何记住一些东西的呢?既然web服务器记不住东西,那我们就尽量在外部记住,相当于服务器给每个client贴一张小纸条。上面记录了服务器返回给我们的一些信息。然后服务器看到这个小纸条就知道我们是谁了。那么是谁生成了cookie?Cookie由服务器生成。下面描述一下cookie生成的过程:当浏览器第一次访问服务器时,此时服务器肯定不知道他的身份,所以创建一个key=value格式的唯一身份数据,放入Set-Cookie字段中,它与响应消息一起发送到浏览器。浏览器看到Set-Cookie字段就知道这是服务器给的标识,所以保存起来,下次会自动把这个key=value值放到Cookie字段中发送给服务器要求。服务器收到请求报文后,发现Cookie字段中有一个值,可以根据这个值来识别用户的身份,进而提供个性化的服务。下面我们用代码来演示下服务器是如何生成的。我们自己搭建了一个后台服务器,是用SpringBoot搭建的,写入SpringMVC的代码如下:@RequestMapping("/testCookies")publicStringcookies(HttpServletResponseresponse){response.addCookie(newCookie("testUser","xxxx""));return"cookies";}项目启动后,我们进入路径http://localhost:8005/testCookies,然后查看发送的请求。可以看到下图是我们第一次访问服务器时发送的请求,可以看到服务器返回的响应中有一个Set-Cookie字段。而里面的key=value值正是我们服务器中设置的值:接下来我们再次刷新页面,可以看到请求体中已经设置了Cookie字段,我们的值也带过来了。这样服务器就可以根据cookie中的值记住我们的信息了:接下来,要不要再发起一次请求?曲奇也会带过来吗?接下来我们输入路径http://localhost:8005进行请求。我们可以看到cookie字段还是被接管了:浏览器cookie存放在哪里?如果您使用的是Chrome浏览器,那么您可以按照以下步骤操作:在电脑上打开Chrome,右上角,点击更多图标→底部的设置,点击高级,在隐私设置和安全下,点击网站设置,点击Cookies→查看所有Cookies和网站数据,然后根据域名搜索托管的Cookies数据。因此浏览器会为您管理cookie数据。如果此时切换到其他浏览器如Firefox,由于刚才在Chrome中保存了cookie,服务器又被包围了。如果你不知道你是谁,你会再次在Firefox上放一个小纸条。cookies中的参数设置说到这里大家应该知道cookies是服务器委托浏览器存储在客户端的一些数据,这些数据通常记录了用户的关键身份信息。因此,cookie需要通过一些其他方式进行保护,以防止泄露或被盗。这些手段就是cookies的属性。下面我简单演示一下这些参数的用法和现象:①Path设置为cookie.setPath("/testCookies"),然后我们访问http://localhost:8005/testCookies,可以看到左边是我们指定的路径是一样的。这就是Cookie出现在请求头中的原因。接下来我们访问http://localhost:8005,发现没有Cookie字段。这是由Path控制的路径。②Domain设置为cookie.setDomain("localhost"),然后我们访问http://localhost:8005/testCookies。我们发现下图左边的字段有cookie,但是当我们访问http://172.16.42.81:8005/testCookies时,我们可以看到下图右边没有cookie的字段。这是由Domain控制的域发送cookie的内容。下面几个参数就不一一演示了。相信这里大家应该对cookies有所了解。SessionCookie保存在客户端,Session保存在服务器端,客户端只保存SessionId。在上面,我们了解了什么是cookie。既然浏览器已经通过cookie实现了有状态的需求,为什么还要多一个Session呢?这里我们想象一下,如果cookie中保存了账户的一些信息,一旦信息被拦截,我们所有的账户信息都会丢失。于是Session就出现了,一个session中重要的信息就保存在Session中。浏览器只记录SessionId,一个SessionId对应一个session请求。@RequestMapping("/testSession")@ResponseBodypublicStringtestSession(HttpSessionsession){session.setAttribute("testSession","thisismysession");返回"testSession";}@RequestMapping("/testGetSession")@ResponseBodypublicStringtestessession(HtsiontpSessionsession=).getAttribute("testSession");returnString.valueOf(testSession);}这里我们写了一个新的方法来测试Session是如何生成的,我们在请求参数中添加了HttpSession会话。然后在浏览器中输入http://localhost:8005/testSession访问,可以看到在服务器的返回头中的Cookie中生成了一个SessionId。那么浏览器就记住了这个SessionId,下次访问的时候可以带上这个Id,然后就可以根据这个Id找到服务器上保存的信息了。这时候我们访问路径http://localhost:8005/testGetSession,发现我们已经获取到了上面Session中存储的信息。那么Session什么时候过期呢?客户端:和Cookie过期一样。如果不设置,默认是关闭浏览器,就没有了。即再次打开浏览器时,初始请求头中没有SessionId。Server:服务器的过期时间,真正过期,即服务器上Session中保存的数据结构多长时间不可用,默认30分钟。既然我们知道Session是在服务器端管理的,看到这里你可能会有几个疑问。Session是在哪里创建的?Session存储在什么数据结构中?接下来,让我们看看Session是如何工作的。管理。会话管理在容器中进行管理。什么是容器?Tomcat、Jetty等都是容器。下面我们以最常用的Tomcat为例,看看Tomcat是如何管理Session的。ManageBase中的createSession用于创建Session:@OverridepublicSessioncreateSession(StringsessionId){//首先判断Session个数是否达到最大值,最大Session个数可以通过参数if((maxActiveSessions>=0)&&设置(getActiveSessions()>=maxActiveSessions)){rejectedSessions++;thrownewTooManyActiveSessionsException(sm.getString("managerBase.createSession.ise"),maxActiveSessions);}//重用或者创建一个新的Session对象,注意是StandardSession//中Tomcat是HttpSession的具体实现类,HttpSession是Servlet规范中定义的接口Sessionsession=createEmptySession();//初始化新Session的值session.setNew(true);session.setValid(true);session.setCreationTime(System.currentTimeMillis());//设置session过期时间为30分钟session.setMaxInactiveInterval(getContext().getSessionTimeout()*60);Stringid=sessionId;if(id==null){id=generateSessionId();}会话。setId(id);//这里会把Session添加到ConcurrentHashMap中sessionCounter++;//将创建时间添加到LinkedList中,并去掉第一次添加的时间//主要是为了清理过期的SessionSessionTimingtiming=newSessionTiming(session.getCreationTime(),0;同步ized(sessionCreationTiming){sessionCreationTiming.add(timing);sessionCreationTiming.poll();}returnssession}至此我们了解了Session是如何创建的。Session创建后,Session会保存在一个ConcurrentHashMap中。可以看到StandardSession类:protectedMap
