Cookie 和 Session机制

news/2024/9/22 16:32:18/

 Cookie

HTTP 协议自身是属于 "无状态" 协议.

"无状态" 的含义指的是:

默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系.

但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的.

例如登陆网站成功后, 第二次访问的时候服务器就能知道该请求是否是已经登陆过了

cookie内容是什么

cookie登录过程

图中的 "令牌" 通常就存储在 Cookie 字段中.

此时在服务器这边就需要记录令牌信息, 以及令牌对应的用户信息, 这个就是 Session 机制所做的工作.

cookie从哪里来

Cookie 中存储了一个字符串,

这个数据可能是客户端(网页)自行通过 JS 写入的,

也可能来自于服务器(服务器在 HTTP 响应的 header 中通过 Set-Cookie 字段把cookie的键值对, 返回给浏览器, 之后再在本地存储).

cookie功能之身份标识

cookie可以在浏览器存储一些"临时性的数据", 其中最典型的一种使用方式就是用来存储"身份标识"

往往可以通过这个字段实现 "身份标识" 的功能.

为了实现身份识别的效果, 不仅仅需要cookie来支持, 在服务器这边也需要一个session机制来支持

后续访问网站的其他页面, 就相当于我去各个科室做检查, 都会在请求的cookie字段中, 带上刚才这里的sessionId(也就是我到了科室, 人家让我先刷就诊卡), 服务器就可以根据sessionId 就知道你的身份信息, 就知道是哪个用户在操作了.

涉及到Cookie和Session 之间的联动

cookie 的本质是浏览器在本地存储 用户自定义数据的一种关键机制

cookie存储在哪里? 怎么存?

浏览器按照不同"服务器域名"存储不同的Cookie

不同域名之间的Cookie是不能干扰的

既然是需要存储, 怎么存?

直接存储到硬盘上是不行的, 不能允许网页能够操作你的电脑文件系统,  为了保证用户上网安全, 浏览器会限制网页直接访问硬盘.

浏览器虽然禁止了直接访问硬盘, 但提供了cookie机制, 允许网页往浏览器这边存储一些自定义的键值对, 这些数据通过了浏览器提供的api 写入特定的文件中

所以cookie是间接存储在浏览器所在电脑的硬盘上

Cookie 存储往往有一个超时间, 超过时间限制就删除了

cookie的内容到哪里去?

后续再访问这个网站中的各个页面, 就会在HTTP请求中自动带上cookie, 服务器就可以进一步的知道客户端的详细资料了(刚才去看病, 各个科室刷就诊卡)

cookie在浏览器这边只能算是"暂存"

真正要让这个数据发挥作用, 还得是服务器来使用

理解会话机制 (Session)

服务器同一时刻收到的请求是很多的. 服务器需要清除的区分清楚每个请求是从属于哪个用户, 就需要在服务器这边记录每个用户令牌以及用户的信息的对应关系.

在上面的例子中, 就诊卡就是一张 "令牌". 要想让这个令牌能够生效, 就需要医院这边通过系统记录每个就诊卡和患者信息之间的关联关系.

会话的本质就是一个 "哈希表", 存储了一些键值对结构. key 就是令牌的 ID(token/sessionId), value就是用户信息(用户信息可以根据需求灵活设计).

sessionId 是由服务器生成的一个 "唯一性字符串", 从 session 机制的角度来看, 这个唯一性字符串称为 "sessionId". 但是站在整个登录流程中看待, 也可把这个唯一性字符串称为 "token".

sessionId 和 token 就可以理解成是同一个东西的不同叫法(不同视角的叫法).

  • 当用户登陆的时候, 服务器在 Session 中新增一个新记录, 并把 sessionId / token 返回给客户端. (例如通过 HTTP 响应中的 Set-Cookie 字段返回).
  • 客户端后续再给服务器发送请求的时候, 需要在请求中带上 sessionId/ token. (例如通过 HTTP 请求中的 Cookie 字段带上).
  • 服务器收到请求之后, 根据请求中的 sessionId / token 在 Session 信息中获取到对应的用户信息, 再进行后续操作.

Servlet 的 Session 默认是保存在内存中的. 如果重启服务器则 Session 数据就会丢失.

Cookie Session 的区别

  • Cookie 是客户端的机制. Session 是服务器端的机制.
  • Cookie 和 Session 经常会在一起配合使用. 但是不是必须配合.
  1. 完全可以用 Cookie 来保存一些数据在客户端. 这些数据不一定是用户身份信息, 也不一定是 token / sessionId
  2. Session 中的 token / sessionId 也不需要非得通过 Cookie / Set-Cookie 传递.

核心方法  

HttpServletRequest 类中的相关方法

 返回值是一个数组, 每个元素是一个Cookie对象, 每个Cookie对象都是有键 也有值

Cookie 类中的相关方法
每个 Cookie 对象就是一个键值对 

   HttpServletResponse 类中的相关方法

 例一

@WebServlet("/getcookie")
public class GetCookieServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取这次请求中的CookieCookie[] cookies = req.getCookies();if(cookies != null) {for(Cookie cookie : cookies) {System.out.println(cookie.getName() + ":" + cookie.getValue());}}else {System.out.println("请求中没有cookie ok");}resp.getWriter().write("ok");}
}

使用费德勒进行抓包发现这这个请求里边并没有cookie

 因此我们需要设置cookie

@WebServlet("/setcookie")
public class SetCookieServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// t通过这个方法 设置自定义的cookie 并返回到浏览器这边Cookie cookie = new Cookie("test", "2023-09-23");resp.addCookie(cookie);Cookie cookie2 = new Cookie("time", "15:17");resp.addCookie(cookie2);resp.getWriter().write("set cookie ok");}
}

 

当访问setcookie 请求 , 代码就会构造set- cookie字段 并放到请求响应resp中, 一并返回给浏览器

此时再访问getcookie, 就有cookie了 

可以看到浏览器已经有了我们自定义的cookie 

例二 

sesion api 涵盖了cookie api

HttpServletRequest 类中的相关方法
 
HttpSession 类中的相关方法
一个 HttpSession 对象里面包含多个键值对 . 我们可以往 HttpSession 中存任何我们需要的信息.

 

 通过一个登录页面 进一步理解cookie 和 session 的关系

服务器后端代码如下: 

@WebServlet("/login")
public class LoginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 1. 获取到用户名和密码String username = req.getParameter("username");String password = req.getParameter("password");if(username == null || password == null || username.equals("") || password.equals("")) {resp.setContentType("text/html; charset=utf-8");resp.getWriter().write("请求参数不完整");return;}// 2. 验证用户名密码是否正确了// 正常的验证, 是从数据库中读取数据// 注册账号就会给数据库插入用户名和密码. 登陆的时候就是验证当前用户名是否存在,以及密码是否匹配// 当前为了简单, 先不引入数据库, 直接通过编码的方式来判定用户名密码// 直接定义, 唯一合法的用户名是 zhangsan 密码是123if(!username.equals("zhangsan")) {resp.setContentType("text/html; charset=utf-8");resp.getWriter().write("用户名错误!");return;}if(!password.equals("123")) {resp.setContentType("text/html; charset=utf-8");resp.getWriter().write("密码错误");return;}// 3. 登录成功 此时可以给这个用户 创建会话了HttpSession session = req.getSession(true);// 在会话中, 可以顺便保存点自定义的数据, 比如保存一个登录的时间戳// setAttribute 后面的value 是一个object 想存啥都可以session.setAttribute("username", username);session.setAttribute("time", System.currentTimeMillis());// 4. 让页面自动转到网站主页.// 此处约定主页的路径是 index (也使用Servlet 生成一个动态页面)resp.sendRedirect("index");}
}
@WebServlet("/index")
public class IndexServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 先验证一下用户的登录状态, 如果未登录, 就要求用户先登录一下HttpSession session = req.getSession(false);if(session == null) {resp.setContentType("text/html; charset=utf-8");resp.getWriter().write("请先登录, 再访问主页");return;}// 已经登录成功了// 就可以取出之前 attributeString username = (String) session.getAttribute("username");Long time = (Long) session.getAttribute("time");System.out.println("username" + username + ",time" + time);//resp.setContentType("text/html; charset=utf-8");resp.getWriter().write("欢迎您," + username + "! 上次登录时间" + time);}
}

 

 具体演示:

HttpSession session = req.getSession(true);

我们先通过login.html页面 向/login发送一个post登录请求(下图), 可见请求中 并未带有cookie 字段

而post请求返回的响应中 已经带有设定好的set-cookie字段, 这个字段就是返回给浏览器, 之后被浏览器存储为cookie

resp.sendRedirect("index");

之后重定向, 浏览器向主页面index  发送get请求, 可以看到此时请求中已经带有cookie

// 先验证一下用户的登录状态, 如果未登录, 就要求用户先登录一下
HttpSession session = req.getSession(false);

此时会话存在且有cookie, 则取cookie中的JsessionId对照服务器中的session(二者一定是一一对照的), 对照成功后返回该session

而此时新建一个页面进行登录操作, 已经带有先前设定好的cookie了

 

回复的响应中也不再需要set-cookie字段 

 

还有一处细节

同一个会话session 中先后设置了不同的属性Attributes, 所以返回时间不一样

 

// 在会话中, 可以顺便保存点自定义的数据, 比如保存一个登录的时间戳
// setAttribute 后面的value 是一个object 想存啥都可以
session.setAttribute("username", username);
session.setAttribute("time", System.currentTimeMillis());

 


http://www.ppmy.cn/news/1124567.html

相关文章

【计算机视觉】2.图像特征提取

图像特征提取 一、颜色特征量化颜色直方图聚类颜色直方图 二、边缘特征边缘边缘定义边缘提取边缘精细 三、特征点的特征描述子Harris角点FAST角点斑点SIFTHaar-like特征SURFORBLBPGabor 一、颜色特征 量化颜色直方图 HSV空间 优势:计算高效 劣势:量化问…

杂谈(2023.9.25)

1.面向对象 对象方法:就是我们面向对象的时候编写的普通的方法,第一个参数默认是self 对象方法可以通过 self 来获取 对象上的所有属性和方法类方法:通过 classmethod 来装饰的方法,第一个参数是cls …

如何借用敏捷实现IT对数字化转型支持 | 2023佛山敏捷之旅成功举办

9月17日,2023年佛山之旅暨DevOps Meetup在佛山圆满落幕。本次大会以助力大湾区金融和互联网企业敏捷DevOps实施和效能提升为主题,吸引了150余位来自各地的金融和互联网企业相关从业人员齐聚一堂,共同探讨行业最佳实践、最新发展趋势以及最新应…

Python函数式编程(一)概念和itertools

Python函数式编程是一种编程范式,它强调使用纯函数来处理数据。函数是程序的基本构建块,并且尽可能避免或最小化可变状态和副作用。在函数式编程中,函数被视为一等公民,可以像值一样传递和存储。 函数式编程概念 编程语言支持通…

K8SYaml文件详解及编写示例

文章目录 一.Yaml文件详解1.Yaml文件格式2.YAML 语法格式 二.Yaml文件编写及相关概念1.查看 api 资源版本标签2.yaml编写案例(1)相关标签介绍(2)Deployment类型编写nginx服务(3)k8s集群中的port介绍&#x…

全自动情感故事对话视频生成神器

搞笑聊天视频是近年来备受欢迎的一种娱乐形式,它能够快速、简单地制作出形象生动、幽默搞笑的对话视频,给人带来欢乐与笑声。而今天,我要向大家介绍的是一款功能强大、操作简单的搞笑聊天视频生成器。 这款聊天视频生成器具备多项令人惊叹的…

ubuntu18.04安装docker

ubuntu18.04安装docker 文章目录 ubuntu18.04安装docker一.安装1.更新软件库索引2.安装一些必要的软件包3.添加Docker的官方GPG密钥4.添加Docker软件库5.再次更新软件库索引6.安装Docker CE7.启动Docker并设置开机启动8.验证Docker安装9.(若要让非root用户可以运行Docker命令)可…

Redis应用(8)——Redis的项目应用:结合SpringBoot如何在Redis里面存对象 RedisUtil工具类的封装 遇到的问题

前言 Redis作为一款优秀的开源、高效的内存数据库,在各种项目中都能见到其身影,熟练使用Redis是程序员必备的技能之一。本系列博客结合应用场景,阐述Redis从安装到使用的,从入门到进阶的相关内容。 本篇博客介绍在Spring项目中&…