会话跟踪技术
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
Cookie
Cookie机制
Cookie技术是客户端的解决方案,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。
说得具体一些:当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP响应体(Response Body)中的,而是存放于HTTP响应头(Response Header);当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置,对于Windows操作系统而言,我们可以从: [系统盘]:\Documents and Settings[用户名]\Cookies
目录中找到存储的Cookie;自此,客户端再向服务器发送请求的时候,都会把相应的Cookie再次发回至服务器。而这次,Cookie信息则存放在HTTP请求头(Request Header)了。有了Cookie这样的技术实现,服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的Cookie得到客户端特有的信息,从而动态生成与该客户端相对应的内容。通常,我们可以从很多网站的登录界面中看到“请记住我”这样的选项,如果你勾选了它之后再登录,那么在下一次访问该网站的时候就不需要进行重复而繁琐的登录动作了,而这个功能就是通过Cookie实现的。
在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。
而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。
Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
如果你把Cookie看成为http协议的一个扩展的话,理解起来就容易的多了,其实本质上Cookie就是http的一个扩展。有两个http头部是专门负责设置以及发送Cookie的,它们分别是Set-Cookie以及Cookie。当服务器返回给客户端一个http响应信息时,其中如果包含Set-Cookie这个头部时,意思就是指示客户端建立一个Cookie,并且在后续的http请求中自动发送这个Cookie到服务器端,直到这个Cookie过期。如果Cookie的生存时间是整个会话期间的话,那么浏览器会将Cookie保存在内存中,浏览器关闭时就会自动清除这个Cookie。另外一种情况就是保存在客户端的硬盘中,浏览器关闭的话,该Cookie也不会被清除,下次打开浏览器访问对应网站时,这个Cookie就会自动再次发送到服务器端。一个Cookie的设置以及发送过程分为以下四步:
-
客户端发送一个http请求到服务器端。
-
服务器端发送一个http响应到客户端,其中包含Set-Cookie头部。
-
客户端发送一个http请求到服务器端,其中包含Cookie头部。
-
服务器端发送一个http响应到客户端。
这个通讯过程也可以用以下下示意图来描述:
在客户端的第二次请求中包含的Cookie头部中,提供给了服务器端可以用来唯一标识客户端身份的信息。这时,服务器端也就可以判断客户端是否启用了cookies。尽管,用户可能在和应用程序交互的过程中突然禁用cookies的使用,但是,这个情况基本是不太可能发生的,所以可以不加以考虑,这在实践中也被证明是对的。
Cookie概述
Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
注意:Cookie功能需要浏览器的支持。如果浏览器不支持Cookie(如大部分手机中的浏览器)或者把Cookie禁用了,Cookie功能就会失效。不同的浏览器采用不同的方式保存Cookie。IE浏览器会在C:\Documents and Settings你的用户名\Cookies
文件夹下以文本文件形式保存,一个文本文件保存一个Cookie。(Cookie的大小不能超过4kb)
Java中使用Cookie
创建Cookie
Servlet中Java代码
//1 创建 Cookie 对象
Cookie cookie = new Cookie("key4", "value4");
//2 通知客户端保存
Cookie resp.addCookie(cookie);
//1 创建 Cookie 对象
Cookie cookie1 = new Cookie("key5", "value5");
//2 通知客户端保存
Cookie resp.addCookie(cookie1);
resp.getWriter().write("Cookie 创建成功");
服务器获取Cookie
服务器获取Cookie只需要一行代码:request.getCookies():返回Cookie[]数组
Cookie的工具类
public class CookieUtils {
/**
* 查找指定名称的 Cookie 对象
* @param name
* @param cookies
* @return
*/
public static Cookie findCookie(String name , Cookie[] cookies){
if (name == null || cookies == null || cookies.length == 0) {
return null;
}
for (Cookie cookie : cookies) {
if (name.equals(cookie.getName())) {
return cookie;}
}
return null;
}
}
Cookie值的修改
方案一:
1、先创建一个要修改的同名(指的就是 key)的 Cookie 对象。
2、在构造器中,同时赋于新的 Cookie 值。
3、调用 response.addCookie( Cookie );
通知客户端保存修改。
Cookie cookie = new Cookie("key1","newValue1");
//调用 response.addCookie( Cookie ); 通知 客户端 保存修改
resp.addCookie(cookie);
方案二:
1、先查找到需要修改的 Cookie 对象。
2、调用 setValue()方法赋于新的 Cookie 值。
3、调用 response.addCookie();
通知客户端保存修改。
Cookie cookie = CookieUtils.findCookie("key2", req.getCookies());
if (cookie != null) {
// 2、调用 setValue()方法赋于新的 Cookie 值。
cookie.setValue("newValue2");
// 3、调用 response.addCookie()通知客户端保存修改
resp.addCookie(cookie);
}
浏览器查看Cookie
谷歌浏览器
火狐浏览器
Cookie的生命控制
Cookie的生命控制指的是如何管理 Cookie 什么时候被销毁(删除)。
setMaxAge();
-
正数,表示在指定的秒数后过期。
-
负数,表示浏览器一关,Cookie 就会被删除(默认值是-1)。
-
零,表示马上删除 Cookie。
在Servlet中设置存活一个小时的Cookie
Cookie cookie = new Cookie("life3600", "life3600");
cookie.setMaxAge(60 * 60); // 设置 Cookie 一小时之后被删除。无效
resp.addCookie(cookie);
resp.getWriter().write("已经创建了一个存活一小时的 Cookie");
马上删除一个Cookie
// 先找到你要删除的 Cookie 对象
Cookie cookie = CookieUtils.findCookie("key4", req.getCookies());
if (cookie != null) {
// 调用 setMaxAge(0);
cookie.setMaxAge(0); // 表示马上删除,都不需要等待浏览器关闭 // 调用
resp.addCookie(cookie);
resp.getWriter().write("key4 的 Cookie 已经被删除");
}
默认的会话级别的 Cookie
Cookie cookie = new Cookie("defalutLife","defaultLife");
cookie.setMaxAge(-1);//设置存活时间
resp.addCookie(cookie);
Cookie有效路径Path的设置
Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器。哪些不发。 path 属性是通过请求的地址来进行有效的过滤。
CookieA path=/工程路径
CookieB path=/工程路径/abc
请求地址如下:
http://ip:port/工程路径/a.html
CookieA 发送
CookieB 不发送
http://ip:port/工程路径/abc/a.html
CookieA 发送
CookieB 发送
Cookie cookie = new Cookie("path1", "path1");
// getContextPath() ===>>>> 得到工程路径
cookie.setPath( req.getContextPath() + "/abc" ); // ===>>>> /工程路径/abc
resp.addCookie(cookie);
resp.getWriter().write("创建了一个带有 Path 路径的 Cookie");
Cookie中文乱码问题
//cookie中存储中文直接报错,需要进行转码后存储
String name = URLEncoder.encode("张三", "UTF-8");
Cookie cookie = new Cookie("name",name);
//解码
String name = URLDecoder.decode(value, "UTF-8");
System.out.println(name);
使用Cookie免用户名登录
login.jsp页面
<form action="http://localhost:8080/cookie_study/loginServlet" method="post">
用户名:<input type="text" name="username" value="${cookie.username.value}"> <br>
密码:<input type="password" name="password"> <br>
<input type="submit" value="登录">
</form>
LoginServlet程序
String username = req.getParameter("username");
String password = req.getParameter("password");
if ("wzg168".equals(username) && "123456".equals(password)) {
//登录 成功
Cookie cookie = new Cookie("username", username);
cookie.setMaxAge(60 * 60 * 24 * 7);//当前 Cookie 一周内有效
resp.addCookie(cookie);
System.out.println("登录 成功");
} else { // 登录 失败
System.out.println("登录 失败");
}
评论区