Cookie 和 Session机制

 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.xdnf.cn/news/141648.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

MATLAB 安装额外工具包

接下里即可搜索并安装 “额外工具包”

从服务器指定位置下载文件

从服务器指定位置下载文件 下载文件转换成流,这里说两种流的方式:1. 文件流2. 字节流 下载文件转换成流,这里说两种流的方式: 1. 文件流 2. 字节流 一,字节流 String filePath“/opt/peoject/file/123/pdf”; //这个是你服务上存放文件位置…

Flutter实现PS钢笔工具,实现高精度抠图的效果。

演示: 代码: import dart:ui;import package:flutter/material.dart hide Image; import package:flutter/services.dart; import package:flutter_screenutil/flutter_screenutil.dart; import package:kq_flutter_widgets/widgets/animate/stack.dart…

UNet网络模型学习总结

github:Machine_Learning/网络模型/UNet at main golitter/Machine_Learning (github.com) 因为VOC数据集太大,上传github很慢,所以就没有上传VOC数据,只有参考的目录位置。 数据集自行下载:https://host.robots.ox.…

Python 逢七拍手小游戏1.0

"""逢七拍手游戏介绍:逢七拍手游戏的规则是:从1开始顺序数数,数到有7,或者是7的倍数时,就拍一手。例如:7、14、17......70......知识点:1、循环语句for2、嵌套条件语句if/elif/e…

旅行季《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著作想象和世界一样宽广

旅行季《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著作想象和世界一样宽广

FPGA设计时序约束一、主时钟与生成时钟

​目录 一、主时钟create_clock 1.1 定义 1.2 约束设置格式 1.3 Add this clock to the existing clock 1.4 示例 1.5 差分信号 二、生成时钟generate_clock 2.1 定义 2.2 格式 2.2.1 by clock frequency 2.2.2 by clock edges 2.2.3 示例 2.2.4 自动生成时钟 2.…

【操作系统笔记十】缓存一致性

CPU 核心之间数据如何传播 高速缓存中的值被修改了,那么怎么同步到内存中呢? ① 写直达(Write-Through)② 写回(Write-Back) 写直达(Write-Through) 简单,但是很慢&am…

springboot项目中定时任务注解@Scheduled未按cron表达式执行

springboot项目中定时任务注解Scheduled未按cron表达式执行 背景问题复现原因分析解决方法其他原因 背景 在将一个类注入到ioc后,其中定义了几个定时任务,分别是每隔十秒执行一次,但实际情况却是半小时才执行一次,故开始分析原因&…

SpringAOP入门案例

package com.elf.spring.aop.aspectj; /*** author 45* version 1.0*/ public interface UsbInterface {public void work(); }package com.elf.spring.aop.aspectj; import org.springframework.stereotype.Component; /*** author 45* version 1.0*/ Component //把Phone对象…

【C++笔记】C++ list类模拟实现

【C笔记】C list类模拟实现 一、初始化和各种构造1.1、准备工作1.2、各种构造和析构 二、插入和删除2.1、插入2.2、删除 三、迭代器3.1、正向迭代器3.2、反向迭代器3.3、提供迭代器位置 四、其他一些接口4.1、链表的长度和判空4.2、返回链表的头尾结点 一、初始化和各种构造 C…

李宏毅hw-10 ——adversarial attack

一、查漏补缺: 1.关于glob.glob的用法,返回一个文件路径的 列表: 当然,再套用1个sort,就是将所有的文件路径按照字母进行排序了 2.relpath relative_path返回相对于基准路径的相对路径的函数 二、代码剖析&#xff…

【红帽】跟着学习如何使用桌面访问命令行

今天我们分享一些红帽Linux的知识,记得关注,会一直更新~ ▶1、以student用户身份并使用student作为密码登录workstation 1.1.在workstation上,从GNOME登录屏幕中单击student用户帐户。系统提示输入密码时,请输入student。 1.2.…

JavaScript系列从入门到精通系列第九篇:JavaScript中赋值运算符和关系运算符以及Unicode编码介绍

一:赋值运算符 1: 右侧的值可以赋值给左侧的变量。 var a 123; console.log(a);//123 2: var a 10; a a 5; a 5; 上边这两个写法是一样的。 3:- var a 10; a a-5; a - 5; 上边这两个写法是一样的。 4:* …

数据备份文件生成--根据表名生成对应的sql语句文件

最近客户有个需求,希望在后台增加手动备份功能,将数据导出下载保存。 当然,此方法不适用于海量数据的备份,这只适用于少量数据的sql备份。 这是我生成的sql文件,以及sql文件里的insert语句,已亲测&#x…

Java抽象类、接口

1.抽象类 1.abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类那么该类就是抽象类。2.抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类3.抽象类,不能使用new关键字来创建对象,它是用来让子类继承的4.抽象方法,只有…

接口测试入门

1. 什么是接口测试 顾名思义,接口测试是对系统或组件之间的接口进行测试,主要是校验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系。其中接口协议分为HTTP,WebService,Dubbo,Thrift,Socket等类型,测试类型又主…

nodejs 如何在npm发布自己的包 <记录>

一、包结构 必要结构: 一个包对应一个文件夹(文件夹名不是包名,但最好与包名保持一致,包名以package.json中的name为主)包的入口文件index.js包的配置文件package.json包的说明文档README.md 二、需要说明的文件 1.配…

【密码学补充知识】

🔑密码学🔒概述 📕 1.基本概念 明文 : 要交换的信息 密文 : 明文经过一组规则变换成看似没有意义的随机消息。 加密 : 明文经过一组规则变换成密文的过程 解密 : 密文恢复出明文的过程 加…

基于 MATLAB 的电力系统动态分析研究【IEEE9、IEEE68系节点】

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…