有些时候对cookiesession理解比较混乱,并且很有可能在面试的时候,也被经常提起cookiesession的区别以及使用。经过查阅一些资料,整理出以下文档

一、cookiesession的概念

1、  cookie

   当一个用户通过Http协议访问一个服务器的时候,服务器会将一些key/value这样的一些键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在相关的条件符合的情况下,浏览器再访问服务器的时候,又会把这些数据完整的带上,返回给服务器。由于HTTP协议是无状态协议,通过cookie的这种方式,服务器就能知道客户端从哪里来的。并且在一些很短的时间呢,用户的一些信息如果被频繁访问,这样服务器就可以做一些缓存等优化,保证访问的速度。

    Http协议中并没有规定相关对cookie大小等的限制,但是由于各家浏览器在实现的过程中的不同,cookie的大小也不同,但是大概为4K ,大多数浏览器对每个站点限制一般为20cookie,当超过这个数量的时候,老的cookie将会被覆盖掉。Cookie在生成的时候,会指定一个expire的值,指定cookie的过期时间,时间超过以后,此Cookie将不能再被使用。必须生成新的cookie,在我们访问网站的时候,通常会见到保存密码多长时间这个选项,如下图:

Cookie和Session解析_Session


  实际上我们登录的这些信息被存储到了客户端浏览器中,然后通过这个cookie来保存我们个人的登录信息,这样我们在下次访问的时候就不需要再重新输入用户名和密码进行登陆。但是当超过设置的expire时间以后,就无法再使用。

  java程序中,我们可以如下代码设置和使用cookie

public String getCookie(Cookie[] cookies,String key){
      if(cookies!=null){
         for(Cookie cookie:cookies){
            if(cookie.getName().equals(key)){
                returncookie.getValue();
            }
         }
      }
      retur nnull;
 }
   publicvoiddoHello(HttpServletRequest request,HttpServletResponse response){
      Cookie[]cookies= request.getCookies();
      
      StringuserName= getCookie(cookies,"username");
      if(userName==null){
         response.addCookie(new Cookie("username","zhangsan"));
      }
      
      response.getHeader("Set-Cookie");
 }


Tomcat创建Set-cookie相应头的时序图

Cookie和Session解析_Cookie_02

   从以上时序图中我们可以看出,在我们通过response.addCooke创建多个Cookie,我们在每次创建Cookie时,都会创建一个以nameSet-CookieMimeHeaders.并且在服务器返回给客户端的时候也不会对相同Header标识的Set-Cookie进行合并。Tomcat源码中可以看出,这段代码位于org.apache.coyote.http11.Http11Processor类的prepareResponse方法中。如下:

Int size = headers.size();
for(int i=0;i<size;i++){
   outputBuffer.setHeader(headers.getName(i),headers.getValue(i));
}

   这段代码清楚的表示,在构Http返回字节流时,是将Header中的所有项顺序的写出,没有做任何修改,所以可以想象浏览器在接受HTTP协议返回的数据时是分别解析每一个Header项的。


2、  session

cookie可以让服务端程序跟踪每个客户的访问,但是每次客户端的访问都必须回传这些cookie的值,如果cookie很多,这样就无形的增加了客户端与服务端的数据量传输,而Session的出现正是为了解决这个问题。

  同一个客户端每次和服务端进行交互时,不需要每次都需要回传所有的Cookie的值,而只需要传回一个ID,这个ID是客户端在第一次访问服务端的时候生成的,而每个客户端都是唯一的,这样每一个客户端就生成了一个唯一的ID,客户端只需要传回这个ID就行了,这个ID通常是NAME为JSSIONID的一个Cookie.所以说Session通常是基于Cookie来工作的,当然当客户端禁用cookie的时候,还有其他的方式进行实现Session,但是就Session和Cookie的关系来说,Session基于Cookie进行工作。


二、session的调用过程

  有了Session ID 的服务端就可以创建HttpSession对象,第一次触发通过调用rquest.getSession()方法,如果当前的Session ID还没有对应的HttpSession对象,则会创建一个HttpSession对象。并将这个对象加到org.apache.catalina.Manager

的session容器中保存,Manager类将会管理所有Session的生命周期,Session过期将会被销毁,服务器关闭,Session将会被序列化到磁盘等。只要这个HttpSession对象存在,用户就可以根据SessionId来获取这个对象,也就达到了状态保持的问题。以下是Session创建的时序图


Cookie和Session解析_Session_03


三、cookie的安全问题

   虽然CookieSession都是可以跟踪客户端的访问记录,但是他们的工作方式显然是不同的。Cookie通过把所有要保存的数据通过HTTP西医的头部从客户端传递到服务器,又从服务器传递给客户端,所有的数据都存储到客户端的浏览器里。所以这些Cookie数据是可以被访问到的。我们通过Firefox是可以访问到记录到浏览器端的用户名和密码的。例如我的百度账号,如下图:

Cookie和Session解析_分布式Session_04


Cookie和Session解析_Cookie_05


不仅可以查看Cookie,我们甚至可以通过一些工具添加,修改Cookie,所以Cooike的安全性是不可保证的。相比较而言,Session的安全性要高很多,因为Session是将数据保存在服务端,指示通过Cookie传递一个JSESSIONID而已。所以Session更适合存储用户隐私和重要数据。

四、分布式session实现思路

    在我们应用在进行部署的时候,现在大多数情况均不是单机部署,而是进行集群的部署,但是这样会导致客户端访问的时候,如果一台服务器挂掉,这样保存在这台服务器上的session就会消失,导致客户登录等相关信息丢失,降低了客户体验的良好性。为了解决以上问题,基本上会有下面两种思路:

  • 在各台服务器间session复制共享

Session复制共享,主要指在集群环境下,各台应用服务器之间进行同步session,使得session保持一致。当一台服务器出现问题时候,负载均衡服务器会把请求负载到另外的一台服务器,由于每台服务器均存储所有服务器的session,这样可以保证请求的连续性。

但是这种方案会有以下不足

  • 技术比较复杂,必须在同一种中间件中进行实现,例如tomcat

  • Session的复制必定会带来性能上的损失,特别是当应用服务器比较多,session存储的内容比较大时。

  • Session内容的序列化,会导致服务器性能下降

  • Session通过广播或者其他形式同步到其他服务器。不管是内网还是外网,同样对网络会造成压力,使之成为瓶颈。

  • 使用session服务器,基于redis等缓存服务器

这种思想是在服务器本机存储一份session,然后再在缓存服务器中存储一份session,当服务器发生故障,在本机找不到session时,可以去缓存服务器中去寻找,再复制到本地,此种为业界常用思路。

Cookie和Session解析_分布式Session_06