一、会话跟踪概述
①为什么需要会话跟踪
Http协议是无状态的,不能保存每次提交的信息,即当服务器返回与请求相对应的应答之后,这次事务的所有信息就丢掉了。
如果用户发来一个新的请求,服务器无法知道它是否与上次的请求有联系。
http协议是一个无状态协议,服务器端无法记录客户端浏览器身份信息。
②什么是会话跟踪
WEB应用中的会话是指一个客户端浏览器与WEB服务器之间连续发生的一系列请求和响应过程。
WEB应用的会话状态是指WEB服务器与浏览器在会话过程中产生的状态信息,借助会话状态,WEB服务器能够把属于同一会话中的一系列的请求和响应过程关联起来。
③会话跟踪常见的两种模式
客户端状态管理技术:将状态保存在客户端(浏览器)。代表性的是Cookie技术
服务器状态管理技术:将状态保存在服务器端(服务器内存中)。代表性的是session技术(服务器传递sessionID时需要使用Cookie的方式)
二、Cookie
Cookie是在浏览器访问WEB服务器的某个资源时,由WEB服务器在HTTP响应消息头中附带传送给浏览器的一片数据,WEB服务器传送给各个客户端浏览器的数据是可以各不相同的。
一旦WEB浏览器保存了某个Cookie,那么它在以后每次访问该WEB服务器时,都应在HTTP请求头中将这个Cookie回传给WEB服务器。
WEB服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将Cookie信息发送给浏览器,浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给WEB服务器。
一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。Cookie以键值对的格式把信息存储在浏览器中!
一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
每个浏览器都一个Cookies存储的区域,Cookie不会相互影响!举例删除火狐浏览器中的Cookie信息,不会影响360浏览器中的Cookie信息!
①创建Cookie
Cookie ck = new Cookie("code",code);
response.addCookie(ck);
②获取Cookie
//获取所有Cookie
Cookie[] cookies = request.getCookies();
//遍历cookies
for (Cookie c : cookies) {
//判断是否是需要的cookie
if (c.getName().equals("code")) {
//保存cookie
code = c.getValue();
}
}
③修改Cookie
只需要保证Cookie的名和路径一致即可修改,只要再写一个Cookie名字和之前的Cookie相同就会自动覆盖之前的Cookie值
Cookie ck = new Cookie("code",code1);
response.addCookie(ck);
④Cookie的生存时间
//>0有效期,单位秒;=0,失效;<0,内存存储
ck.setMaxAge(-1);
⑤Cookie的编码与解码
编码可以使用java.net.URLEncoder类的encoder(String str,String encoding)方法,
解码可以使用java.net.URLDecoder类的decode(String str,String encoding)方法。
⑥Cookie的路径问题
cookie 一般都是由于用户访问页面而被创建的,可是并不是只有在创建 cookie 的页面才可以访问这个cookie。在默认情况下,出于安全方面的考虑:
1、服务器端每次访问的cookie是每次请求头中发送给服务器端的
2、客户端每次请求只发送当前路径下和“直系”关系的父路径的cookie(父路径的页面是不能访问子路径和兄弟路径的cookie的)
3、setcookie如果不设置路径,默认为当前页面的路径,父亲路径的页面是无法访问的
4 "/"这个根路径可以在任何路径下访问,求简单可以把cookie都放在这里。/ 路径 这个网站所有地方都可以取出来
⑦Cookie的不可跨域名性
浏览器在发送请求之前,首先会根据请求url中的域名在cookie列表中找所有与当前域名一样的cookie,然后再根据指定的路径进行匹配,如果当前请求在域匹配的基础上还与路径匹配那么就会将所有匹配的cookie发送给服务器。
只要域名不同,就无法相互访问彼此的Cookie,比如百度就无法访问到谷歌的Cookie,www.baidu.com也无法访问news.baidu.com的Cookie。
如果使用Cookie的setDomain方法,就可以了,代码如下:
Cookie c = new Cookie("name","value");
c.setDomain(".baidu.com")
⑧设置Cookie的路径
通过Cookie的setPath方法设置路径。
⑨Cookie的特点
优点:
可配置到期规则 Cookie 可以在浏览器会话结束时到期,或者可以在客户端计算机上无限期存在,这取决于客户端的到期规则。
不需要任何服务器资源 Cookie 存储在客户端并在发送后由服务器读取。由浏览器自动发送!
简单性 Cookie 是一种基于文本的轻量结构,包含简单的键值对。
数据持久性 虽然客户端计算机上 Cookie 的持续时间取决于客户端上的 Cookie 过期处理和用户干预,Cookie 通常是客户端上持续时间最长的数据保留形式
缺点:
大小受到限制 大多数浏览器对 Cookie 的大小有 4096 字节的限制,尽管在当今新的浏览器和客户端设备版本中,支持 8192 字节的 Cookie 大小已愈发常见。
用户配置为禁用 有些用户禁用了浏览器或客户端设备接收 Cookie 的能力,因此限制了这一功能。
潜在的安全风险 Cookie 可能会被篡改。用户可能会操纵其计算机上的 Cookie,这意味着会对安全性造成潜在风险或者导致依赖于 Cookie 的应用程序失败。
三、Session
Session用于跟踪客户的状态。服务器端存储用户会话信息!
Session指的是在一段时间内,单个客户与Web服务器的一连串相关的交互过程。
在一个Session中,客户可能会多次请求访问同一个网页,也有可能请求访问各种不同的服务器资源。
每个用户使用浏览器访问服务器,服务器会给每个用户分配一个session!
①Session工作原理
session被用于表示一个持续的连接状态,在网站访问中一般指代客户端浏览器的进程从开启到结束的过程。session其实就是网站分析的访问(visits)度量,表示一个访问的过程。
session的常见实现形式是会话cookie(session cookie),即未设置过期时间的cookie,这个cookie的默认生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。实现机制是当用户发起一个请求的时候,服务器会检查该请求中是否包含sessionid,如果未包含,则系统会创造一个名为JSESSIONID的输出 cookie返回给浏览器(只放入内存,并不存在硬盘中),并将其以HashTable的形式写到服务器的内存里面;当已经包含sessionid是时,服务端会检查找到与该session相匹配的信息,如果存在则直接使用该sessionid,若不存在则重新生成新的 session。这里需要注意的是session始终是由服务端创建的,并非浏览器自己生成的。但是浏览器的cookie被禁止后session就需要用get方法的URL重写的机制或使用POST方法提交隐藏表单的形式来实现。
Session依赖于Cookie!因为JSESSIONID 是每个用户的sesson的唯一标志,服务器中有很多用户正咋访问服务器,服务器会为每个用户创建sessionID
②Session的生命周期
Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。
Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。
Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。
③Session对浏览器的要求
虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为Session需要使用Cookie作为识别标志。HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。
该Cookie为服务器自动生成的,它的maxAge属性一般为–1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。
因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,因此会共享一个Session。
注意:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在链接上右击,在弹出的快捷菜单中选择“在新窗口中打开”时,子窗口便可以访问父窗口的Session。
④获得Session
HttpSession session = request.getSession();
⑤使用Session绑定对象
使用HttpSession的setAttribute(属性名,Object)方法;
session.setAttribute("username", name);
⑥删除Session
使用HttpSession的invalidate方法。
⑦Session超时
HttpSession的最后一程访问时间和当前时间的差距大于了指定的最大空闲时间,这时服务器就会销毁Session对象。默认的空闲时间为30分钟。
使用HttpSession的setMaxInactiveInterval设置,单位秒
Session失效的几种情况
1、超过了设置的超时时间
2、主动调用了invalidate方法
3、服务器主动或异常关闭
注意:浏览器关闭并不会让Session失效
⑧浏览器禁用Cookie的解决方案
如果浏览器禁用Cookie,session还能用吗?
答:不能,但又其他的解决方案
服务器在默认情况下,会使用Cookie的方式将sessionID发送给浏览器,如果用户禁止Cookie,则sessionID不会被浏览器保存,此时,服务器可以使用如URL重写这样的方式来发送sessionID。
总结:
1.会话跟踪(会话管理):
浏览器和服务器之间进行通讯,采用的HTTP协议!但是Http协议本身就是一个无状态的协议!
2.会话跟踪的技术2种:
客户端的技术 Cookie (键值对)
服务器端技术 Session (键值对) session.setArribute("key",object值);
3.session和cookie对比:
存储的位置不同:
Cookie存储在浏览器中!
Session存储在服务器端!
存储的时间问题:
Cookie可以人工设置失效时间!如果不设置 默认-1(浏览器关闭失效),还可以使用setMaxAge(秒);
Session的有效期默认是30分钟(滑动计时时间),也可以手动设置session失效时间!setMaxInactiveInterval设置,单位秒
存储数据的问题:
Cookie存储的键值对的文本数据,数据量有限制。浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB
Sesion存储的session.setArribute("key",object值);可以存任何类型的数据!
数据的安全性:
Cookie存储在浏览器中,Cookie存储的是非敏感数据,因为随时被清空!
Session存储的服务器端,安全性好!(存储用户的登录信息)每个用户服务器端都有一个对应的自己的会话!
Session严重依赖于Cookie!因为SessionID就是一段Cookie信息!
以下代码是使用Cookie和Session的实例,其中使用Cookie进行登录勾选记住密码的任务,Session进行验证码的验证和安全退出的功能,验证码使用到了kaptcha,这是个第三方类库,需要的可以百度下载下来使用。
request.setCharacterEncoding("utf-8");
String name = request.getParameter("username");
String pass = request.getParameter("password");
HttpSession session = request.getSession();
// 首先判断用户是否选择了记住登录状态
String[] isUseCookies = request.getParameterValues("isUseCookie");
if (isUseCookies != null && isUseCookies.length > 0) {
// 获得用户名和密码,使用URLEncoder解决无法在Cookie当中保存中文字符串的问题
String username = URLEncoder.encode(name, "utf-8");
String password = URLEncoder.encode(pass, "utf-8");
// 将获得的用户名放入Cookie对象中
Cookie usernameCookie = new Cookie("username", name);
Cookie passwordCookie = new Cookie("password", pass);
// 设置最大生存日期为10天
usernameCookie.setMaxAge(864000);
passwordCookie.setMaxAge(864000);
// 保存Cookie对象
response.addCookie(usernameCookie);
response.addCookie(passwordCookie);
} else {
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie c : cookies) {
if (c.getName().equals("username") || c.getName().equals("password")) {
c.setMaxAge(0);
response.addCookie(c);
}
}
}
}
//通过kaptcha进行验证码的判断,session获取
String k = (String) session.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
String str = request.getParameter("r");
str = new String(str.getBytes("iso-8859-1"), "utf-8");
boolean flag = us.login(name, pass);
if (flag && k.equals(str)) {
session.setAttribute("username", name);
response.sendRedirect("BookServlet.action?action=show");
} else if (!(k.equals(str))) {
response.getWriter().write("<script>alert('验证码错误!');location.href='login.jsp';</script>");
} else {
response.getWriter().write("<script>alert('账号或密码错误!');location.href='login.jsp';</script>");
}
HttpSession session = request.getSession();
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie c : cookies) {
if (c.getName().equals("username") || c.getName().equals("password")) {
c.setMaxAge(0);
response.addCookie(c);
}
}
}
if (session.getAttribute("username") != null) {
session.removeAttribute("username");
if (cookies != null && cookies.length > 0) {
}
}
if (session.getAttribute("password") != null) {
session.removeAttribute("password");
}
response.sendRedirect("/booksystem/login.jsp");