cookie、session机制及相关内容详解

来源:互联网 发布:备考中级会计 知乎 编辑:程序博客网 时间:2024/06/05 05:23

cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。

cookie和session的由来:
早期的web应用或者说早期的网站都是一种处理静态资源的网站,功能主要是查看文档,看看图片,而现在互联网的网站更准确的定义应该是互联网软件即网站就是软件,网站所代表的软件和早期软件的定义是不一样的,早期的软件都是在单机环境下运行,而互联网的普及让软件和网络技术融合在一起。

这就要求网站所代表的软件应该要有一个对事务处理的记忆功能,事务处理的记忆功能就是我们常说的要有状态。

而实现web应用技术的核心http协议是一个无状态的协议,http这种设计也许是历史遗留问题,也许无状态的http是最简单也是最有效的通讯方式,但是当网站成为软件后,状态的保持就是一个很重要的功能。
HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。

因此在web应用开发里就出现了保持http链接状态的技术:一个是cookie技术,另一种是session技术。

cookie机制:

cookie技术是客户端的解决方案,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。
过程:
第一次,客户端将信息放在HTTP响应体(Response Body)中,发给服务器,服务器回传的时候就将这些信息放进HTTP响应头(Response Header)中了;然后客户端将这些信息以文本形式存储在本地;以后客户端再请求服务器时就都把该信息放进HTTP请求头中,服务器每次也返回来;服务器每次就分析存放在请求头中的cookie得到客户端特有的信息,动态生成响应;

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
request.getCookie()获取客户端提交的所有Cookie(以Cookie[]数组形式返回)
response.addCookie(Cookie cookie)向客户端设置Cookie。
Cookie对象使用key-value属性对的形式保存用户状态,一个Cookie对象保存一个属性对,一
个request或者response同时使用多个Cookie。

Cookie的不可跨域名性
Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。
Cookie在客户端是由浏览器来管理的。浏览器能够保证Google只会操作Google的Cookie而不会操作Baidu的Cookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。Google与Baidu的域名不一样,因此Google不能操作Baidu的Cookie。

常用属性:
String name:该Cookie的名称。Cookie一旦创建,名称便不可更改
Object value:该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码
int maxAge:该Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1。cookie.setMaxAge(Integer.MAX_VALUE);// 设置生命周期为MAX_VALUE(永远有效)
boolean secure:该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false,即可以被http这种不安全的,不经过加密的方式传输;
String path:该Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”
String domain:可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”
String comment:该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明
int version:该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范

要想修改Cookie只能使用一个同名的Cookie来覆盖原来的Cookie,达到修改的目的。删除时需要新建一个同名的cookie,然后把maxAge修改为0,再覆盖原来的即可。
注意:修改删除时,新建的cookie只有value和maxAge可以修改,其余的不可以修改,否则被认为是不同的,不能覆盖;
注意:从客户端读取Cookie时,包括maxAge在内的其他属性都是不可读的,也不会被提交。浏览器提交Cookie时只会提交name与value属性。maxAge属性只被浏览器用来判断Cookie是否过期。

cookie的隐私安全机制能禁止网站非法获取其他网站的cookie,但是同一个域名下的多个二级域名是可以被设置为相同cookie;

保存登录信息有多种方案。最直接的是把用户名与密码都保持到Cookie中,下次访问时检查Cookie中的用户名与密码,与数据库比较。这是一种比较危险的选择,一般不把密码等重要信息保存到Cookie中。还有一种方案是把密码加密后保存到Cookie中,下次访问时解密并与数据库比较。这种方案略微安全一些。如果不希望保存密码,还可以把登录的时间戳保存到Cookie与数据库中,到时只验证用户名与登录时间戳就可以了。这几种方案验证账号时都要查询数据库。
另一种方案,只在登录时查询一次数据库,以后访问验证登录信息时不再查询数据库。实现方式是把账号按照一定的规则加密后,连同账号一块保存到Cookie中。下次访问时只需要判断账号的加密规则是否正确即可。
具体做法:比如把账号保存到名为account的Cookie中,把账号连同密钥用MD1算法加密后保存到名为ssid的Cookie中。验证时验证Cookie中的账号与密钥加密后是否与Cookie中的ssid相等。
该加密机制中最重要的部分为算法与密钥。由于MD1算法的不可逆性,即使用户知道了账号与加密后的字符串,也不可能解密得到密钥。因此,只要保管好密钥与算法,该机制就是安全的。

session机制
Web应用程序中还经常使用Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制,使用上比Cookie简单一些,相应的也增加了服务器的存储压力。

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。
客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

每个来访者对应一个Session对象,所有该客户的状态信息都保存在这个Session对象里。Session对象是在客户端第一次请求服务器的时候创建的。Session也是一种key-value的属性对。

HttpSession session = request.getSession(); // 获取Session对象
session.setAttribute(“loginTime”, new Date()); // 设置Session中的属性

getSession(boolean create)来获取Session:如果该客户的Session不存在,request.getSession()方法会返回null,而getSession(true)会先创建Session再将
Session返回。

Session机制决定了当前客户只会获取到自己的Session,而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。Session的使用比Cookie方便,但是过多的Session存储在服务器内存中,会对服务器造成压力。

Session的生命周期:
Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。
Session在用户第一次访问服务器的时候自动创建。
Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。

Session保存在服务器的一个StandardManager的 session集合中,取出的是StandardSession对象;
StandardManager类负责Servlet容器中所有的StandardSession对象的生命周期管理;
Servlet容器关闭,则将未过期的session持久化为一个session.ser文件中,servlet重启,则再重新读取解析出所有session对象,重新保存在StandardManager的session集合中。

Session的有效期:
由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。Tomcat中Session的默认超时时间为20分钟。
Session的超时时间为maxInactiveInterval属性,可以通过对应的getMaxInactiveInterval()获取,通过setMaxInactiveInterval(longinterval)修改。Session的超时时间也可以在web.xml中修改。另外,通过调用Session的invalidate()方法可以使Session失效。

Session对浏览器的要求:
Session需要使用Cookie作为识别标志。HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JsessionID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。
新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。
如果客户端浏览器将Cookie功能禁用,或者不支持Cookie怎么办?例如,绝大多数的手机浏览器都不支持Cookie。Java Web提供了另一种解决方案:URL地址重写。(将cookie写进URL中传输)

Session中禁止使用Cookie
注意:该配置只是禁止Session使用Cookie作为识别标志,并不能阻止其他的Cookie读写。也就是说服务器不会自动维护名为JSESSIONID的Cookie了,但是程序中仍然可以读写其他的Cookie。

cookie与session的关系:
cookie和session的方案虽然分别属于客户端和服务端,但是服务端的session的实现对客户端的cookie有依赖关系的,上面我讲到服务端执行session机制时候会生成session的id值,这个id值会发送给客户端,客户端每次请求都会把这个id值放到http请求的头部发送给服务端,而这个id值在客户端会保存下来,保存的容器就是cookie,因此当我们完全禁掉浏览器的cookie的时候,服务端的session也会不能正常使用。

sessionID如何产生?由谁创建?存在哪里?
sessionID是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,有一个sessionid和它对应。tomcat生成的sessionid叫做jsessionid。
session在访问tomcat服务器HttpServletRequest的getSession(true)的时候创建,tomcat的ManagerBase类提供创建sessionid的方法:随机数+时间+jvmid;(tomcat的session的id值生成的机制是一个随机数加时间加上jvm的id值,jvm的id值会根据服务器的硬件信息计算得来,因此不同jvm的id值都是唯一的)
存储在服务器的内存中,tomcat的StandardManager类将session存储在内存中,也可以持久化到file,数据库,memcache,redis等。客户端只保存sessionid到cookie中,而不会保存session,session销毁只能通过invalidate或超时,关掉浏览器并不会关闭session。

session实际使用带来的问题:跨站点的session共享问题
session的实现机制都是web容器里内部机制,这就导致一个web容器里所生成的session的id值是不同的,因此当一个请求到了A服务器,浏览器得到响应后,客户端存下的是A服务器上所生成的session的id,当在另一个请求分发到了B服务器,B服务器上的web容器是不能识别这个session的id值,更不会有这个sessionID所对应记录下来的信息,这个时候就需要两个不同web容器之间进行session的同步。
Tomcat容器有一个官方的解决方案就是使用apache+tomcat+mod_jk方案,当一个web容器里session的信息发生变化后,该web容器会向另一个web容器进行广播,另一个web收到广播后将session信息同步到自己的容器里,这个过程是十分消耗系统资源,当访问量增加会严重影响到网站的效率和稳定性。
当用户请求网站的时候会先将请求发送给硬件的负载均衡设备,该设备可以截获客户端发送过来的session的id值,然后我们根据这个id值找到产生这个session的服务器,将请求直接发送给这台服务器。这种解决方案看起来解决了session共享问题,其实结果是将集群系统最终变回了单点系统,如果处理请求的web容器挂掉了,那么用户的相关会话操作也就废掉了。此外,这种做法也干扰了负载均衡服务器的负载均衡的计算,让请求的分发并不是公平的。

由上所述,session一共有两个问题需要解决:

1) session的存储应该独立于web容器,也要独立于部署web容器的服务器;

2)如何进行高效的session同步。
在讲到解决这些问题之前,我们首先要考虑下session如何存储才是高效,是存在内存、文件还是数据库了?文件和数据库的存储方式都是将session的数据固化到硬盘上,操作硬盘的方式就是IO,IO操作的效率是远远低于操作内存的数据,因此文件和数据库存储方式是不可取的,所以将session数据存储到内存是最佳的选择。因此最好的解决方案就是使用分布式缓存技术。
例如:memcached和redis,将session信息的存储独立出来也是解决session同步问题的方法。

原创粉丝点击