这篇文章彻底了解什么是Cookie、Session、Token。叔叔:什么是马?夏洛特:马冬梅。叔叔:没什么?夏洛特:马冬梅。叔叔:那匹马呢?夏洛特:好的,先生,您应该先冷静下来。在理解这三个概念之前,我们首先要明白HTTP是一种无状态的Web服务器。什么是无国籍?就像上面夏洛特烦恼中的经典对话场景一样,一个对话完成后,下一个对话完全不知道上一个对话发生了什么。如果只是用来管理web服务器中的静态文件,那么不管对方是谁,直接从磁盘中读取文件发送出去即可。但是随着网络的不断发展,比如电子商务中的购物车,只有记住了用户的身份,才能进行接下来一系列的动作。所以在这一点上我们需要我们的无状态服务器记住一些东西。那么网络服务器如何记住一些东西呢?既然web服务器记不住东西,那我们就想办法在外部记住,相当于服务器给每个客户端都贴上一张小纸条。上面记录了服务器返回给我们的一些信息。然后服务器看到这个小纸条就知道我们是谁了。那么是谁生成了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中的值记住我们的信息了。另一个请求呢?Cookie也会带过来吗?接下来我们输入路径http://localhost:8005请求。我们可以看到Cookie字段还是被接管了。那么浏览器cookie存储在哪里呢?如果您使用的是Chrome浏览器,则可以按照以下步骤操作。在计算机上打开Chrome。右上角一次性点击更多图标->底部设置,点击高级,在隐私设置和安全下,点击网站设置,点击Cookies->查看所有Cookies和网站数据,然后根据域名搜索.管理cookie数据。因此,是浏览器为您管理cookie数据。如果此时切换到其他浏览器如Firefox,由于刚才在Chrome中存储了cookie,服务器又被阻塞了。如果你不知道你是谁,就再贴一下Firefox的小纸条。cookies中的参数设置说到这里大家应该知道cookies是服务器委托浏览器存储在客户端的一些数据,这些数据通常记录了用户的关键身份信息。因此,cookie需要通过一些其他方式进行保护,以防止泄露或被盗。这些手段就是cookies的属性。参数名作为后端设置方法Max-Age设置cookie的过期时间,单位秒cookie.setMaxAge(10)Domain指定cookie所属域名cookie.setDomain("")Path指定路径cookie属于哪个cookie.setPath("");HttpOnly告诉浏览器,这个cookie只能通过浏览器的Http协议传输,禁止其他访问cookie。setHttpOnly(true)Secure告诉浏览器这个cookie只能在Https安全协议中传输,如果是Http则禁止传输cookie.setSecure(true)下面简单演示一下这几个参数的用法和现象。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的字段。这是发送cookie的Domain控制的域名。下面几个参数就不一一演示了。相信这里大家应该对cookies有所了解。Session>Cookie保存在客户端,Session保存在服务器端,客户端只保存SessionId就可以了。我们了解什么是cookie。既然浏览器已经通过cookies实现了有状态的需求,为什么还要再来呢?会话呢?这里我们想象一下,如果cookie中保存了一些账户信息,一旦信息被拦截,我们所有的账户信息都会丢失。于是就有了Session,在一个session中保存了Session中的重要信息,浏览器只记录SessionId。一个SessionId对应一个会话请求。@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什么时候过期呢?Client:同cookie过期,如果不设置,默认是关闭浏览器就没有了,即再次打开浏览器时,初始请求头中没有SessionId。server:服务器的过期时间是真的过期了,就是服务器上Session中保存的数据结构有多久不可用了,默认是30分钟。既然我们知道Session是在服务器端管理的,那么看到这里你可能会有几个疑问,Session是在哪里创建的呢?Session存储在什么数据结构中?接下来我们看一下Session是如何管理的。会话管理在容器中进行管理。什么是容器?Tomcat、Jetty等都是容器。下面我们以最常用的Tomcat为例,看看Tomcat是如何管理Session的。ManageBase中的createSession用于创建Session。@OverridepublicSessioncreateSession(StringsessionId){//先判断会话数是否达到最大值,最大会话数可以通过参数设置if((maxActiveSessions>=0)&&(getActiveSessions()>=maxActiveSessions)){拒绝会议++;thrownewTooManyActiveSessionsException(sm.getString("managerBase.createSession.ise"),maxActiveSessions);}//复用或者新建一个Session对象,注意是Tomcat中的StandardSession//是HttpSession的具体实现类,而HttpSession是Servlet规范中定义的接口Sessionsession=createEmptySession();//初始化新Session的值session.setNew(true);session.setValid(true);session.setCreationTime(System.currentTimeMillis());//设置Session过期时间为30分钟//这里将Session添加到ConcurrentHashMapsessionCounter++;//将创建时间添加到LinkedList中,并去掉第一次添加的时间//主要是为了清理过期的SessionSessionTimingtiming=newSessionTiming(session.getCreationTime(),0);synchronized(sessionCreationTiming){sessionCreati钛ming.add(timing);sessionCreationTiming.poll();}returnssession}至此我们明白了Session是如何创建的。Session创建后,Session会保存在一个ConcurrentHashMap中。您可以看到StandardSession类。protectedMap
