Cookie
一、会话概述
1、会话:一次会话中包含多次请求和响应。
一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止。
Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求。
2、功能:
在一次会话的范围内的多次请求间,共享数据
3、方式:
客户端会话技术:Cookie
服务器端会话技术:Session
二、Cookie 概述
1、Cookie 是客户端会话技术,将数据保存到客户端,是服务器通知客户端保存键值对的一种技术;
2、客户端有了 Cookie 后,每次请求都发送给服务器;
3、每个 Cookie 的大小不能超过 4KB;
三、Cookie 的使用
1、创建 Cookie 对象
Cookie 的 JDK 已经内置好的一个对象,可以通过构造方法直接来创建 cookie 对象;
构造方法:
Cookie cookie = new Cookie(String name,String value);
创建一个 Cookie 对象,name 表示 cookie 的值,value表示 cookie 里面存放的值。
使用 response 对象可以将 cookie 发送到客户端
发送方法:
response.addCookie(Cookie cookie)
原理图:
代码示例:
1 protected void createCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
2 //1 创建 Cookie 对象
3 Cookie cookie = new Cookie("key1", "value1");
4 //2 通知客户端保存 Cookie
5 resp.addCookie(cookie);
6 //1 创建 Cookie 对象
7 Cookie cookie1 = new Cookie("key2", "value2");
8 //2 通知客户端保存 Cookie
9 resp.addCookie(cookie1);
10 resp.getWriter().write("Cookie 创建成功");
11 }
注意:
① 可以同时创建多个 cookie 对象,但是一定要用 addCookie() 方法设置到响应里;
② cookie() 不能包含中文和特殊字符,值不应包含空格、方括号、圆括号、等号、逗号、双引号、斜杠、问号、at 符号、冒号和分号。空值在所有浏览器上的行为不一定相同。
2、服务器获取 Cookie
在服务器获取客户端的 Cookie,需要使用 HttpServletRequest 的方法:
Cookie[] request.getCookies():获取客户端所有的 cookie 对象
String getName() 获取某个 cookie的 key(名)
String getValue() 获取某个 cookie的 value(值)
原理图:
代码示例:
把根据名称查找 Cookie 抽取成工具类:
1 public class CookieUtils {
2 /**
3 * 查找指定名称的 Cookie 对象
4 * @param name
5 * @param cookies
6 * @return
7 */
8 public static Cookie findCookie(String name , Cookie[] cookies){
9 if (name == null || cookies == null || cookies.length == 0) {
10 return null;
11 }
12 for (Cookie cookie : cookies) {
13 if (name.equals(cookie.getName())) {
14 return cookie;}
15 }
16 return null;
17 }
18 }
获取 Cookie:
1 protected void getCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
2 Cookie[] cookies = req.getCookies();
3 for (Cookie cookie : cookies) {
4 // getName 方法返回 Cookie 的 key(名)
5 // getValue 方法返回 Cookie 的 value 值
6 resp.getWriter().write("Cookie[" + cookie.getName() + "=" + cookie.getValue() + "] <br/>");
7 }
8 Cookie iWantCookie = CookieUtils.findCookie("key1", cookies);
9
10 // 如果不等于 null, 说明赋过值, 也就是找到了需要的 Cookie
11 if (iWantCookie != null) {
12 resp.getWriter().write("找到了需要的 Cookie");
13 }
14 }
3、Cookie 值的修改
方案一:
① 先创建一个要修改的同名(key)的 Cookie 对象;
② 在构造器中,同时赋于新的 Cookie 的值;
③ 调用 response.addCookie(Cookie);
代码示例:
1 // 1、 先创建一个要修改的同名的 Cookie 对象
2 // 2、 在构造器, 同时赋于新的 Cookie 值。
3 Cookie cookie = new Cookie("key1","newValue1");
4 // 3、 调用 response.addCookie( Cookie ); 通知 客户端 保存修改
5 resp.addCookie(cookie);
方案二:
① 先查找到需要修改的 Cookie 对象;
② 调用 setValue() 方法赋于新的 Cookie 值;
③ 调用 response.addCookie() 通知客户端保存修改;
代码示例:
1 // 1、 先查找到需要修改的 Cookie 对象
2 Cookie cookie = CookieUtils.findCookie("key2", req.getCookies());
3 if (cookie != null) {
4 // 2、 调用 setValue()方法赋于新的 Cookie 值。
5 cookie.setValue("newValue2");
6 // 3、 调用 response.addCookie()通知客户端保存修改
7 resp.addCookie(cookie);
8 }
三、使用浏览器查看 Cookie
1、谷歌浏览器查看 Cookie
2、火狐浏览器查看 Cookie
四、实现原理
Cookie 基于响应头 set-cookie 和请求头 cookie 实现的。
原理示意图:
第一次访问服务器时,服务器就会给浏览器一个 “身份识别卡”,浏览器每次向服务器发送请求时都会带着这个 “身份识别卡”,当服务器看到这个 卡片时就可以识别浏览器的身份。
实际上这个 “身份识别卡” 就是服务器发送的一个响应头:
如上图 Set-Cookie 这个响应头就是服务器在向浏览器发送的 “身份识别卡”,这个响应头名字是 Set-Cookie,后面的 JSESSIONID=95A92EC1D7CCB4ADFC24584CB316382E 和 Path=/Test_cookie,是两组键值对的结构就是服务器为这个“身份识别卡”设置的信息。浏览器收到该信息后就会将它保存到内存或硬盘中。
当浏览器再次向服务器发送请求时就会携带这个 Cookie 信息:
这是浏览器发送的请求报文,中间画红框的就是 Cookie 信息,即浏览器带着“身份识别卡”访问服务器,服务器就可以根据 Cookie 信息来判断浏览器的状态。
五、Cookie 生命控制(有效性)
Cookie 是存储在浏览器中的,但是一般情况下浏览器不可能永久保存一个 Cookie,一是占用硬盘空间,二是 Cookie 可能只在某一时刻有用没必要长久保存。
Cookie 的生命控制指的是如何管理 Cookie 什么时候被销毁(删除)
可以通过下面的方法来进行设置:
setMaxAge()设置 Cookie 的最大生存时间以秒为单位
正数:表示在指定的秒数后过期
负数:意味了 cookie 不会被持久存储,表示浏览器一关,Cookie 就会被删除
零:Cookie 立即失效,表示马上删除 Cookie,下次浏览器发送请求将不会携带该 Cookie
不设置:默认值是 -1,则默认当前会话有效,关闭浏览器失效。(会话级别)
六、Cookie 有效路径 Path的设置
Cookie 的 Path 属性可以有效的过滤哪些 Cookie 可以发送给服务器,哪些不发送。
通过Cookie的 setPath() 来设置路径,这个路径是由浏览器来解析的所以/代表服务器的根目录,如果不设置,默认在访问 “/项目名” 下的资源时携带。
path 属性是通过请求的地址来进行有效的过滤。
图解:
Demo:
1 protected void testPath(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
2 Cookie cookie = new Cookie("path1", "path1");
3 // getContextPath() ===>>>> 得到工程路径
4 cookie.setPath( req.getContextPath() + "/abc" ); // ===>>>> /工程路径/abc
5 resp.addCookie(cookie);
6 resp.getWriter().write("创建了一个带有 Path 路径的 Cookie");
7 }
五、Cookie 细节
1、一次可不可以发送多个 cookie?
可以一次发送多个cookie对象。
可以创建多个 cookie 对象,使用 response 调用多次 addCookie 方法发送 cookie 即可。
2、cookie 在浏览器中保存多长时间?
(1)默认情况下,当浏览器关闭后,cookie 数据被销毁
(2)持久化存储
setMaxAge(int seconds) // 单位为秒
① 正数:将 cookie 数据写到硬盘的文件中。持久化存储,并指定 cookie 存活时间,时间到了,cookie 文件自动失效;
② 负数:默认值,关闭浏览器 cookie 销毁;
③ 零:删除当前的 cookie 信息;
3、cookie 是否能够存储中文
(1)在 Tomcat 8 之前,cookie 中不能直接存储中文数据。
如果需要将中文数据转码(一般采用 URL 编码)
(2)在 Tomcat 8 之后,cookie 支持中文数据。
但是对特殊字符(如:空格等)还是不支持,建议使用 URL 编码存储,用URL解码解析。
4、cookie 共享问题?
假设在一个 Tomcat 服务器中,部署了多个 web 项目,那么在这些 web 项目中 cookie 能不能共享?
默认情况下 cookie 不能共享。
解决方法:
setPath(String path)
使用上面的方法可以实现 cookie 共享,设置 cookie 的获取范围。默认情况下,设置当前的虚拟目录。
如果要在一个服务器间共享,则可以将 path 设置为"/" ,代表一个服务器内都可以共享。
5、不同的 tomcat 服务器 cookie 之间如何共享?
setDomain(String path);
通过设置该方法,如果设置一级域名相同,那么多个服务器之间cookie可以共享。
Demo:
setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享
六、Cookie 的特性
1、特点
(1)cookie 存储数据在客户端浏览器,不安全,容易被篡改
(2)浏览器对于单个 cookie 的大小由限制(4KB左右),而且对同一个域名下的总 cookie 的数量也有限制(20个)
2、作用
(1)cookie 一般用于存储少量的不太敏感的数据;
(2)在不登录的情况下,完成服务器对客户端的身份识别;
3、缺点
(1)Cookie 是为请求或响应报文发送,无形中增加了网络流量;
(2)Cookie 是明文传送的安全性差;
(3)各个浏览器对 Cookie 有限制,使用上有限制;