当前位置: 首页 > news >正文

“会话技术”——Cookie_(2/2)原理与使用细节

经过Cookie的快速入门与代码使用。如果想深入理解Cookie的技术实现,就得去理解它的原理。
且有些时候使用Cookie,还要根据需求设置存活期限以及确定Cookie获取范围等其他细节。最后,我们会总结Cookie这门客户端会话技术的作用。


一、原理

注:我们还是使用简易图画进行辅助理解

注:这是上一节写的代码(两个Servlet),这里将这个例子使用一下分析Cookie的原理

所谓分析Cookie原理,正是分析: 服务器端如何响应时发送Cookie,以至于浏览器端识别了还自动保存;并且CookieDemo2怎么获取到的Cookie,即浏览器怎么就携带了Cookie信息进行了下一次请求。

1.1 分析:

 其实不管发送数据也好,还是获取数据(站在服务器端看)也好,它们在客户端与我端(服务端)中间都是以HTTP协议进行交互——响应和请求一定是遵循HTTP协议的

首先,客户端发送了第一次请求,请求访问了服务器端的资源——CookieDemo1。

CookieDemo1收到了请求,于是以“发送Cookie”进行处理数据并响应了(确实向浏览器发送了Cookie),刚刚说“所有的客户与服务器端的响应请求都遵循HTTP协议”。所以那实际上,“发送Cookie”时,怎么发送呢? 服务器(response端)会在响应报文中设置一个名为“Set-Cookie”的响应头,该响应头的值以键值对的形式呈现,恰好可用于存储Cookie

于是浏览器端会收到来自服务器端的响应报文,发现响应报文的响应头有“set-Cookie”。浏览器因为熟读HTTP协议,所以遵循协议:如果浏览器收到了set-Cookie响应头,它应该将这个头里携带的数据(“name=Bear”)保存到自己本地中。

而在第二次请求时,HTTP协议又规定了:浏览器应该在下一次请求中将保存的数据(“name=Bear”)放进一个Cookie的请求头中(作为值)。浏览器端会在请求报文中设置一个Cookie请求头,其值类型也为键值对,恰好也用来放Cookie数据。

 于是CookieDemo2能从请求头中获取到Cookie信息。但是,在咱们使用Cookie代码获取请求里的Cookie,并不是操作所谓的“Cookie这个请求头”,而是怎么? 

Cookie[] cookies = request.getCookies();
//这样一个名叫getCookies()的方法

 这也得多亏了JAVA EE 内部实现的API,封装的库方法(函数)。让我们调用里的方法就能发送和获取Cookie,而方法便是去和请求头或者响应头打交道,我们放心调用就行。

1.2 看看:

初见"set-Cookie"响应头和“Cookie”请求头,不熟悉很正常,多看几眼。我们在浏览器抓包

1.2.1抓包

(浏览器端)按F12键 ,接着如图操作:

我们现在运行,访问CookieDemo1—— :抓抓它的响应包: 

是吧,这发送Cookie响应时会真的有一个响应标头Set-Cookie。

那如果我们继续请求CookieDemo2:抓抓它的请求报文,是不是在存储Cookie后下一次请求就会在请求头里捎带上Cookie数据。

确实是。 

 二、Cookie的细节

2.1 一次可不可以发送多个cookie呢?

了解了原理这个问题== 响应报文set-Cookie的值可以是多个键值对吗? 

我们修改修改CookieDemo1:

// 原
@WebServlet("/CookieServlet01")
public class CookieServlet01 extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{// 1. 创建Cookie,绑定数据Cookie cookie = new Cookie("name","Bear");// 2. 发送Cookie对象response.addCookie(cookie);}}

我们再创建一个Cookie,让response调用两次addCookie();

protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{// 1. 创建Cookie,绑定数据Cookie cookie = new Cookie("name","Bear");Cookie cookie2 = new Cookie("place","Toilet");//新建// 2. 发送Cookie对象response.addCookie(cookie);response.addCookie(cookie2);//连着发送}

运行这段代码,即重新请求CookieDemo1,抓抓它的请求包:

答案:一次可以发送多个Cookie。

为了完整,我们再访问打印Cookie的那个Servlet,抓抓这回的请求包:

都存了,是的,刚刚响应发来的Cookie都存进浏览器了;这会儿,也全部放进请求头Cookie了。

2.2 Cookie在浏览器中能保存多长时间?

默认情况下,当浏览器关闭后,Cookie数据被销毁;因为默认存到浏览器内存里,程序结束,内存就会删除数据。

如果想设置持久化存储,我们这里再学习一个Cookie的方法:

cookie.setMaxAge(int seconds)
//参数是int类型,单位为秒数。
// int 是有符号整型,于是根据取值的不同,该方法会实现不同的效果

 若seconds 为 正数 :意味着 a. 将Cookie数据写到硬盘的文件中、持久化存储。

b. 规定了该Cookie存活的时间

若seconds 为 0 : 意味着删除该Cookie。设置完cookie的MaxAge,需要将这个Cookie发送给客户端。

为什么秒数为0,就意味着删除? 这句话看似只有1个问,其实有2个答案。
1. Cookie 最大存活期限为0,那么就意味着“不存在”。
2. Cookie是存在用户端的数据,服务器端不能直接操作客户端的数据,所以服务器想要删除Cookie就用这种方式:设MaxAge=0,再响应发送。

若seconds为 负数:意味着默认设置(所以设为负数,跟不设置MaxAge效果一样:一旦关闭浏览器,存在内存里的Cookie就会被释放,失效)

代码实践timing :

我们新建一个CookieServlet03来创建和发送Cookie。

/** CookieDemo03 用来创建和发送Cookie* 分别设置存活期限:*  ^ 正数*  ^ 负数*  ^ 0* */
@WebServlet("/CookieServlet03")
public class CookieServlet03 extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{// 1. 创建Cookie,绑定数据// 2. 设置Cookie的存活期限// 3. 发送Cookie对象}
}

 写入核心代码:

        // 1. 创建Cookie,绑定数据Cookie cookie = new Cookie("name","bear");// 2. 设置Cookie的存活期限cookie.setMaxAge(30);//设置正数的存活期限,代表了:1.将Cookie数据写到硬盘的文件中。持久化存储。2.Cookie存活时间// 3. 发送Cookie对象response.addCookie(cookie);

 验证逻辑:我们重新打开浏览器,先访问CookieServlet03(客户端收到cookie会存起来),再请求访问CookieDemo02(这时可在Eclipse控制台打印出Cookie信息)。

如果在30秒之内,我们关闭浏览器又访问CookieServlet02,按理可以获取并打印这个Cookie:

如果超过30秒后,我们再次访问CookieServlet02,我们再看控制台:

负数和0的取值,也是同样验证步骤。

 2.3 cookie能不能存中文?

在tomcat 8之前,不能存中文。

那怎么办? 需要将中文数据转码 —— 一般采用URL编码(如:%E3)

在tomcat 8之后 ,cookie支持中文数据,但还是不支持特殊字符。

我们现在使用的是tomcat 9,故tomcat8之前的不做演示。

运行服务器,访问CookieServlet03,再访问CookieServlet02打印:

以上验证,tomcat8以上,Cookie能存中文。

2.4 cookie获取范围多大?

假设在一个服务器(也就是一个tomcat)中,部署了多个web项目,那么在这些web项目中cookie能不能共享?

图:工程目录下的项目们

经过作者的超绝不经意安排,有以下两个项目: 

 它们的cookieDemo2和cookieServlet02都是获取request的Cookies并打印。

这时我们验证的问题:项目1下的cookieServlet01发送给客户端的Cookie,会被项目2下的cookieDemo2获取到吗(即跨项目的cookie能获得吗)

项目1下的CookieServlet01

我们接下来就访问这个Servlet:

接着我们访问项目2下的cookieDemo2: 

 最后得到验证:

假设在一个服务器中,部署了多个web项目,那么在这些web项目中cookie能不能共享?
默认情况下cookie不能共享

假如就有这个需求,需要一个服务器上多个项目共享Cookie,该如何呢?

2.4.2 多个项目共享Cookie

之所以Cookie多个项目不能共享,是因为默认情况下,客户端存储的Cookie目录是以项目名为目录的:

项目不同,项目名就不同。自然该目录下就不会出现其他项目名的Cookie。

这里引入Cookie的另一个方法:

Cookie.setPath(String Path);
//参数为字符串类型,表示该cookie的存储路径。

 运行:

 此时若我们再访问另一个项目下的打印Servlet:

 

再看控制台,成功打印了项目1刚刚存的Cookie。

所以,想要实现一个服务器下多个项目下的Cookie共享:就setPath()。

2.4.3 多个服务器Cookie共享

其实还是同样的道理,调用cookie方法,但是是不同的方法:

setDomain(String path)
// 参数:字符串类型,设置域名

如果设置一级域名相同,那么多个服务器之间的cookie可以共享
如果SetDomain(“.baidu.com”),那么tieba.baidu.com和news.baidu.com中cookie可以共享
因为这两个服务器都是baidu管辖下的,那何必要设置两个服务器呢?是因为如果一个服务器承受不了大量的用户请求访问。

比较浅显的解释,但这里简单提出,仅为知识体系的完整。后面再次接触的时候就会深入应用。

三、Cookie的特点和作用:

特点:

1.    cookie存储数据在客户端浏览器
2.    浏览器对于单个cookie的大小有限制(4kb左右) 以及 对于同一个域名下的总cookie数量也有限制(20个)
这Cookie的名字也暗示了存不了多少数据。Cookie——“小甜点”,饭后甜食或者下午茶小点心,不能当主食。

 作用:

1.    Cookie一般用于存储少量的不太敏感的数据
2.    在不登录的情况下,完成服务器对客户端的身份识别;而登录的话,就是在数据库里获取数据

“不太敏感”,存在客户端,咱们一抓包或者在“开发者工具”里就能看到,服务器这边还能删除……无不昭示着客户端安全性不太高,尽量不存敏感数据。

 第二点还挺重要,需要好好理解:

我们来到baidu的主页面:

我们在输入框输入问题:

 如果我们既不登录,又想实现输入问题的时候没有自动联想:

我们再次来到主页面,此时还是未登录状态:

若我关闭浏览器,再次进入baidu,输入问题也没有自动联想。为什么呢?是因为刚刚的“保存设置”时发出请求,baidu响应了这些设置,数据以set-Cookie标头响应过来。

浏览器保存这些信息(Cookie),而我们再次来到baidu主页面:我们的请求会自动携带Cookie。而baidu服务器则会获取请求里的Cookie,再将我们的需求响应给我们。

这就是Cookie:在未登录的状态下 ,服务器完成对客户端身份的识别。如果登录的话,服务器就直接在它的数据库里提取数据了。


下一节:Cookie的实战应用

相关文章:

  • 【二叉树】java源码实现
  • 中小企业MES系统概要设计
  • 数字智慧方案6213丨智慧园区规划方案(63页PPT)(文末有下载方式)
  • 【学习笔记】第十章:序列建模:递归神经网络(RNN)
  • Python 数据智能实战 (8):基于LLM的个性化营销文案
  • Redis总结及设置营业状态案例
  • 分发饼干之 双数组匹配问题 (双指针 or 二分)
  • 【质量管理】现代TRIZ中问题识别中的功能分析——相互接触分析
  • 【算法题】荷兰国旗问题[力扣75题颜色分类] - JAVA
  • Rust 学习笔记:关于枚举与模式匹配的练习题
  • 从0搭建Transformer
  • 大学之大:瑞典皇家理工学院2025.5.2
  • 纯原生Java实现:获取整个项目中指定接口所有的实现类
  • 柔性超声耦合剂的选择与设计-可穿戴式柔性超声耦合剂面临的难题
  • [面试]SoC验证工程师面试常见问题(三)
  • 冯·诺依曼体系:现代计算机的底层逻辑与百年传承
  • 深度学习框架PyTorch——从入门到精通(YouTube系列 - 4)——使用PyTorch构建模型
  • 实现水平垂直居中的多种方法
  • 多模态RAG演进-MRAG1.0->MRAG2.0->MRAG3.0
  • 【验证技能】VIP项目大总结
  • 本周看啥|《乘风》迎来师姐们,《天赐》王蓉搭Ella
  • 来上海喝云南咖啡!上海国际咖啡文化节助力咖啡产业破圈出海
  • 网警查处编造传播“登顶泰山最高可得3万奖金”网络谣言者
  • 剑指3000亿产业规模,机器人“武林大会”背后的无锡“野望”
  • 湖北鄂州通报4所小学学生呕吐腹泻:供餐企业负责人被采取强制措施
  • 宁波市纪委监委通报4起违反中央八项规定精神典型问题