参考资料:(2篇)JavaWeb基础系列(四)Session和CookieHttp是无状态的吗?Session、Cookie、TokenSharing的区别【采访+工作】-云+社区-腾讯云(tencent.com)5.1Stateless是指协议对事务处理没有记忆功能。缺少状态意味着如果后面的处理需要它,则必须重新传输较早的信息,这可能导致每个连接传输的数据量增加。另一方面,当服务器不需要以前的信息时,响应速度更快。直观来说,每个请求都是独立的,与前后请求没有直接联系。为什么不把http协议改进成有状态的呢:原来的http协议只是用来浏览静态文件的,无状态的协议就足够了,实现起来的负担很轻。随着web的发展,它需要变得有状态,但是没有必要去修改http协议让它成为有状态的。因为我们经常会在某个网页停留很长时间,然后进入另一个网页,如果在这两个页面之间保持状态,成本是非常高的。5.2cookie和session技术——session技术HTTP本身是一个无状态的连接协议。为了支持客户端和服务端的交互,我们引入会话技术来交互存储状态。Session技术分为Cookie和Session。会话技术的定义:从打开浏览器访问某个站点到关闭浏览器的整个过程称为会话。session技术就是记录本次session中client的状态和数据。5.2.1Cookies在客户端存储用户数据,减轻服务器端的存储压力。如果安全性不好,客户端可以清除cookie。Cookies不能跨域名,即访问不同域名的浏览器只会携带该域名对应的cookies,而某个域名只能操作该域名的cookies。Cookie在客户端由浏览器管理,浏览器可以保证Cookie不能跨域名,从而保证用户的隐私。工作原则:给每个客户发一张通行证,来访者必须携带自己的通行证。这样,服务器就可以从护照上确认客户端的身份。实现方法:将登录的账号、密码等登录信息保存在cookie中,并控制cookie的有效期,下次访问时再对cookie中的登录信息进行验证。实施方案:方案一:最直接的方法是将用户名和密码保存在cookie中,下次访问时查看cookie中的用户名和密码,并与数据库进行比对。这是一个比较危险的选择。通常,密码等重要信息不会保存在cookie中。非常危险的方案2:将密码加密后保存在cookie中,下次访问时解密并与数据库进行比对。这个方案稍微安全一些。如果不想保存密码,也可以将登录时间戳保存在cookie和数据库中,然后只验证用户名和登录时间戳。仍然危险方案三:只在登录时查询数据库一次,以后访问验证登录信息时不再查询数据库。本方案将账号保存在名为account的cookie中,并将账号和密钥用MD5算法加密后保存在名为ssid的cookie中。只需验证帐号与密钥加密后的ssid是否相等即可。加密机制中最重要的部分是算法和密钥。由于MD5算法的不可逆性,即使用户知道帐号和加密后的字符串,也无法解密获得密钥。因此,只要密钥和算法保存完好,该机制就是安全的。5.2.2Session在服务器端存储数据,相对安全,占用服务器资源,增加服务器压力;原理:为每个client创建一个内存空间来存放客户数据,但是client每次都需要携带一个SessionID到server去寻找自己的内存空间。所以Session的实现是基于Cookie的,Session需要使用Cookie来存储客户唯一的SessionID。打个比方:相当于程序在服务器上创建的一个客户文件。当客户来访时,只需要查询客户档案表即可。Create:第一次执行request.getSession()时创建Destroy:服务器(异常)关闭时;session过期/失效(默认30分钟,从不操作服务器端资源开始计时);实现方式:一般浏览器都提供了两种保存方式,还有一种方式是程序员利用html隐藏域来自定义实现:1)使用cookies保存,这是最常用的方式。服务器通过设置cookie将SessionID发送给浏览器。如果我们不设置这个过期时间,那么这个cookie就不会保存在硬盘上。当浏览器关闭时,cookie就会消失,sessionID也会丢失。如果我们将这个时间设置为几天后,那么这个cookie就会保存在客户端的硬盘中,即使关闭浏览器,这个值仍然存在,下次访问时也会发送给服务器相应的网站。2)使用URL附加信息的方法,也就是我们经常看到的JSP网站会有aaa.jsp?JSESSIONID=*。这个方法和第一种方法一样,没有设置cookie过期时间。3)在页面表单中添加一个隐藏域。这种方法其实和第二种方法一样,只是前者通过GET方式发送数据,而后者使用POST方式发送数据。但显然后者更麻烦。5.2.3Cookie和Session的关系Cookie是一个实际的、具体的东西,定义在http协议的头域中。会话是一个抽象的概念。开发者为了实现中断和延续等操作,将客户端与服务端的一对一交互抽象为“会话”,进而衍生出“会话状态”,这就是会话的概念。即session描述了一种通信会话机制,cookie只是实现该机制的主流方案中的一个参与者。一般用于保存sessionID。5.3Session共享5.3.1Session-Cookie技术运行过程当用户登录时,请求到达服务器,服务器调用getSession()方法判断会话是否存在。如果不存在,则新建一个session,通过其算法为session生成一个随机数作为sessionId,开发者可以在session中存储一些用户信息;第二次请求,如果获取到用户信息,则getSession()方法判断session存在,取出session,而不是新建session,从而从session信息中获取用户的相关信息.客户端请求时,将cookie信息存储在请求头中,发送给服务器;当服务器响应时,将cookie信息放在响应中,并发回给客户端。5.3.2getSession()方法做了什么?对于第一次用户请求,客户端本地没有任何数据,即cookie为空,请求发送给服务端。request会在getSession()中解析,发现约定的cookie为null,则认为没有session,因此会重新创建一个session对象;session创建后,将sessionid放入response中返回给客户端,客户端将cookie保存在response中;再次请求,服务端getSession()会重新解析请求获取cookie,并在其中找到sessionId,然后根据sessionId去服务端寻找,然后得到上次创建的session对象,则认为认证成功。Java伪代码(图片来源见水印):5.3.3如何实现session共享根据上面提到的session-cookie机制,session保存在各个服务器中,但是在集群中,有多个服务器,每个各行其是,势必会导致在本服务器登录成功获取session,而在另一台服务器上,获取不到session,导致认证失败,对用户极其不友好。几种处理方法:1、找一个公共空间存放session,而不是将session存放在集群节点的某台服务器上。此时每台服务器都可以访问这个空间,从而实现会话共享;2、采用同步机制,实时同步各个服务器的session信息;实施方案:将session持久化到数据库,即使用数据库来存储session。数据库正好是我们平时使用的公共存储空间,比如使用mysql数据库。优点:就地取材,符合大部分人的想法,简单易用,不需要额外做太多编码工作缺点:对mysql性能要求高,访问mysql需要从连接池中获取连接,而且由于大部分请求需要需要进行登录认证,所以对数据库的操作非常频繁。当用户数量达到一定程度时,很容易造成数据库瓶颈,不适合处理高并发。使用redis共享会话。Redis是一个键值存储系统。可以简单理解为数据库。与传统数据库不同的是,它把数据存储在内存中,并且自带内存到硬盘的序列化策略,即内存中的数据按照策略同步到磁盘,避免数据丢失是目前比较流行的解决方案。优点:不需要增加数据库的压力,因为数据是存放在内存中的,所以读取速度非常快,性能高,可以处理各种类型的数据。缺点:增加一些额外的代码来操作redis。使用memcache同步session,memcache可以分布式,可以将服务器中的内存组合起来形成一个“内存池”,作为一个公共空间,保存session信息。注:MemCache是一个免费、开源、高性能、分布式分布式内存对象缓存系统,用于动态Web应用程序以减少数据库的负载。它通过在内存中缓存数据和对象来减少数据库读取次数,从而提高网站访问速度。优点:数据存储在内存中,读取速度很快,性能好;缺点:memcache将内存划分成大大小小的各种规格的存储块,不能充分利用内存,造成内存碎片,浪费资源。不够,也会发生内存溢出。使用NFS共享会话。NFS是NetworkFileServer共享服务器的缩写,最早由Sun开发,用于解决Unix网络主机之间的目录共享。选择一个公共的NFS作为共享服务器来存储所有的session数据,从这里获取各个服务器需要的session。优点:更好的实现会话共享;缺点:成本较高,个人难以实施。NFS依赖于复杂的安全机制和文件系统
