【JavaEE】你真的了解Cookie和Session吗?

news2024/9/26 3:28:27

  • 博主简介:想进大厂的打工人
  • 博主主页:@xyk:
  • 所属专栏: JavaEE初阶 

目录

文章目录

一、什么是Cookie

二、什么是Session

三、Cookie和Session有什么不同

四、关于Sessionid

五、关于浏览器禁止Cookie

六、如何考虑分布式Session问题?

七、Servlet模拟登录


一、什么是Cookie

HTTP Cookie是浏览器在本地存储数据的一种机制,是服务器通过 Set-Cookie 字段发送到浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再次发送请求时被携带并一起发送到服务器上,它通常被用来保存当前用户的登录状态。

Cookie 主要用于以下三个方面:

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)

  • 个性化设置(如用户自定义设置、主题等)

  • 浏览器行为跟踪(如跟踪分析用户行为等)

那么在Cookie保存用户身份标识,这样的应用场景中,此时身份标识如何分配?以及身份信息具体如何存储?都是需要服务器的支持,这时候Session(会话)就出现了~

二、什么是Session

Session(会话)就是服务器用来实现用户身份区分的一种机制,通常是和Cookie配合使用的,Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的页面之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去,当客户端关闭会话,或者Session超时失效时会话结束。

三、Cookie和Session有什么不同

1.作用范围不同,Cookie保存在客户端,Session保存在服务器端

2.存取方式不同,Cookie只能保存ASCII,Session可以存任意数据类型,一般我们可以在Session中存一些常用变量信息或者User对象等

3.有效期不同,Cookie可以设置长时间保持,比如我们经常使用的默认登录,Session一般失效时间较短,客户端关闭或者超时都会失效

4.隐私策略不同,Cookie在客户端,比较容易被获取,Session在服务端,安全性相对较好

5.存储大小不同,单个Cookie保持数据不能超过4K,Session可存储远高于Cookie

四、关于Sessionid

当浏览器第一次访问服务器时,服务器会根据用户提交的相关信息,创建一个Session对象,返回一个Cookie并且生成一个唯一标识 Sessionid 一起返回,可以理解为服务器端有一个全局的哈希表,Sessionid作为key,Session对象作为value。

当浏览器第二次访问服务器,请求会自动找到Cookie中的Sessionid信息,并且去服务器端的全局哈希表中查询是否存在Session对象,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。

五、关于浏览器禁止Cookie

既然服务端是根据 Cookie 中的信息判断用户是否登录,那么如果浏览器中禁止了 Cookie,如何保障整个机制的正常运转?

1.每次请求中都携带一个 Sessionid的参数,也可以Post的方式提交,也可以在请求的地址后面拼接xxx?SessionID=123456...

2.Token 机制。Token 机制多用于 App 客户端和服务器交互的模式,也可以用于 Web 端做用户状态管理。

Token 的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。Token 机制和 Cookie 和 Session 的使用机制比较类似。

当用户第一次登录后,服务器根据提交的用户信息生成一个 Token,响应时将 Token 返回给客户端,以后客户端只需带上这个 Token 前来请求数据即可,无需再次登录验证。

六、如何考虑分布式Session问题?

在互联网公司为了可以支撑更大的流量,后端往往需要多台服务器共同来支撑前端用户请求,那如果用户在 A 服务器登录了,第二次请求跑到服务 B 就会出现登录失效问题。

分布式 Session 一般会有以下几种解决方案:

  • Nginx ip_hash 策略,服务端使用 Nginx 代理,每个请求按访问 IP 的 hash 分配,这样来自同一 IP 固定访问一个后台服务器,避免了在服务器 A 创建 Session,第二次分发到服务器 B 的现象。

  • Session 复制,任何一个服务器上的 Session 发生改变(增删改),该节点会把这个 Session 的所有内容序列化,然后广播给所有其它节点。

  • 共享 Session,服务端无状态话,将用户的 Session 等信息使用缓存中间件来统一管理,保障分发到每一个服务器的响应结果都一致。

建议采用第三种方案。

七、Servlet模拟登录

在HttpServletRequest类中,可以使用getSession来获取或者创建会话,getCookies可以获取请求中的Cookie列表

方法描述
HttpSession
getSession()
在服务器中获取会话. 参数如果为 true, 则当不存在会话时新建会话; 参数如果
为 false, 则当不存在会话时返回 null
Cookie[]
getCookies()
返回一个数组, 包含客户端发送该请求的所有的 Cookie 对象. 会自动把
Cookie 中的格式解析成键值对.

调用getSession方法所做的事情:

getSession 有一个 boolean 类型的参数, 如果参数是 true, 它有如下行为:

1.读取 cookie 里的 sessionId 字段.
2.根据 sessionld 来查询对应的 HttpSession 对象在服务器上是否存在.
3.如果不存在, 就创建一个新的会话, 即创建一个新的 HttpSession 对象, 并生成一个唯一的 sessionId, 会以新生成的 sessionId 作为 Key, 生成的 HttpSession 对象作为 Value, 以键值对形式储存到类似于 Hash 的结构中, 然后将 sessionId 设置到响应报文中的 set-Cookie 字段返回给浏览器.
4.如果存在就直接返回查询到的 HttpSession 对象.


如果参数是 false, 行为如下:

1.读取 cookie 里的 sessionId 字段.
2.根据 sessionld 来查询对应的 HttpSession 对象在服务器上是否存在.
3.如果不存在, 直接返回 null.
4.如果存在就直接返回查询到的 HttpSession 对象.

HttpSession对象

这个对象也可以看作是一个哈希表,是以键值对的形式存储数据的,我们可以往 HttpSession 中存任何我们需要的信息

方法描述
Object getAttribute(String
name)
该方法返回在该 session 会话中具有指定名称的对象,如果没有
指定名称的对象,则返回 null.
void setAttribute(String
name, Object value)
该方法使用指定的名称绑定一个对象到该 session 会话
boolean isNew()判定当前是否是新创建出的会话

我们这个涉及到两个页面,第一个是登录页面,第二个是登录成功后要跳转的主页面

登录页面包含两个输入框 (用来输入用户名和密码) 和一个登录按钮, 点击登录按钮就会发起一个 HTTP 请求, 服务器处理这个请求的时候就会验证用户名和密码, 验证通过就会跳转到主页, 主页就简单的显示出当前用户的用户名就行了.

涉及两个Servlet,一个是登录LoginServlet,一个是IndexServlet

第一步,约定前后端接口

约定用户名zhangsan,密码123,使用Post请求,响应采用302重定向

img

获取主页,采用Get请求,响应返回一个页面

  

前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录界面</title>
</head>
<body>
    <form action="login" method="post">
        <input type="text" name="username">
        <input type="text" name="password">
        <input type="submit" value="登录">
    </form>
</body>
</html>

LoginServlet:

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 先从请求中拿到用户名和密码.
        // 为了保证读出来的参数也能支持中文, 要记得设置请求的编码方式是 utf8
        req.setCharacterEncoding("utf8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //2.验证用户名密码是否正确
        if (username == null || password == null || username.equals("") || password.equals("")){
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前输入的用户名或密码不能为空!");
            return;
        }
        // 此处假定用户名只能是 zhangsan 或者 lisi. 密码都是 123
        // 正常的登录逻辑, 验证用户名密码都是从数据库读取的.
        if (!username.equals("zhangsan") && !username.equals("lisi")){
            //用户名有问题
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("用户名或密码有误");
            return;
        }
        if (!password.equals("123")){
            //密码有问题
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("用户名或密码有误");
            return;
        }
        // 3. 用户名和密码验证 ok, 接下来就创建一个会话.
        //    当前用户处于未登录的状态, 此时请求的 cookie 中没有 sessionId
        //    此处的 getSession 是无法从服务器的 哈希表 中找到该 session 对象的.
        //    由于此处把参数设为 true 了, 所以就允许 getSession 在查询不到的时候, 创建新的 session 对象和 sessionId
        //    并且会自动的把这个 sessionId 和 session 对象存储的 哈希表 中.
        //    同时返回这个 session 对象, 并且在接下来的响应中会自动把这个 sessionId 返回给客户端浏览器.
        HttpSession session = req.getSession(true);
        // 接下来可以让刚刚创建好的 session 对象存储咱们自定义的数据. 就可以在这个对象中存储用户的身份信息.
        session.setAttribute("username",username);
        // 4. 登录成功之后, 自动跳转到 主页
        resp.sendRedirect("index");
    }
}

IndexServlet:

@WebServlet("/index")
public class IndexServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 此处禁止创建会话. 如果没找到, 认为用户是未登录的状态!!
        // 如果找到了才认为是登录状态.
        HttpSession session = req.getSession(false);
        if (session == null){
            //未登录状态
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前用户未登录!");
            return;
        }
        String username = (String) session.getAttribute("username");
        if (username == null){
            // 虽然有会话对象, 但是里面没有必要的属性, 也认为是登录状态异常.
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前用户未登录!");
            return;
        }

        // 如果上述检查都 ok, 接下来就直接生成一个动态页面.
        resp.setContentType("text/html;charset=utf8");
        resp.getWriter().write("欢迎你!"+username);
    }
}

存session对象:

取session对象:

当再次访问时,可以看见Cookie中携带Sessionid,不用重新登录了~ 

关于 IDEA 集成的 Tomcat 环境有一些需要注意的点, 正常来说, 上面说的 sessionId 并不会一直存在下去, 比如 Tomcat 服务器重新启动的时候, 原来服务器在内存中维护的会话 Hash 表就应该没有了, 此时再次访问, 就应该出现 sessionld 查不到, 就被识别成 “未登录” 状态了。

但是有些版本 Smart Tomcat 为了方便程序猿调试程序, 会在停止服务器的时候把会话持久化保存, 并且在下次启动的时候自动把会话恢复到内存中, 在这种情况下会话是不丢失的.

但如果是手动部署程序到 Tomcat, 则会话默认还是在内存中, 重启服务器是会丢失的.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/738453.html

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

相关文章

springboot请求重定向失败问题解决方案

今天晚上在写登录页面时&#xff0c;发现自己的首页无法正常访问&#xff0c;用户名和密码正常的情况下还是无法访问首页。于是开始进行debug&#xff0c; 程序执行至此处时无任何异常&#xff0c;但是就是在进行重定向页面时出现了404&#xff0c;在检查导航栏后发现地址栏也发…

做好POC测试 需要重点关心的5点

在日常POC测试过程中&#xff0c;往往遇到&#xff1a;测试计划时间结束才达到测试目标&#xff0c;导致结果未记录&#xff1b;不了解测试达标要求&#xff0c;未达到测试要求&#xff0c;后期大量的工作进行补救&#xff1b;测试遇到的问题&#xff0c;没有充分地相互沟通等问…

Dell Inspiron 15-3567电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板Dell Inspiron 15-3567 处理器Intel Core i5 Kabylake, 7200U, 2.70 GHz已驱动 内存16GB LPDDR4X 3200MHz已驱动 硬盘三星 MZVLW1T0HMLH-000L2 (…

pycharm找不到conda可执行文件怎么办?

问题&#xff1a;pycharm配置conda环境找不到conda可执行文件 解决办法&#xff1a; 1. 找到 anaconda 安装目录&#xff08;D:\Users\wl\anaconda3&#xff09; 2. 打开pycharm &#xff08;看图吧<手动狗头>&#xff09; 找到anaconda3\condabin\conda.bat 选择你要…

【从删库到跑路】MySQL数据库的 存储引擎

&#x1f38a;专栏【MySQL】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【如愿】 &#x1f970;欢迎并且感谢大家指出小吉的问题 文章目录 &#x1f33a;存储引擎简介&#x1f384;查询当前数据库支持的存储引擎&#x1f384;…

C++笔记之是否知道了一个数组首元素的地址就可以获取该整个数组?-面试问题

C笔记之数组名和指针GPT问答记录 事前提要&#xff1a;前段时间去面一个公司&#xff0c;面试官说知道了一个数组首元素的地址&#xff0c;就可以获取该整个数组&#xff0c;我当时就困惑&#xff0c;不知道大小和长度&#xff0c;只知道地址怎么就能获取。但也没反驳面试官&a…

ChatGPT炒股:批量下载北交所上市公司的招股说明书

打开北京证券交易所官网&#xff0c;点击发行上市&#xff0c;然后点击公开发行信息披露&#xff0c;然后在查询框里面输入关键词&#xff1a;在北京证券交易所上市招股说明书&#xff0c;然后选择时间&#xff0c;点击查询&#xff0c;就可以看到所有北交所上市公司的招股说明…

数据集【NO.13】复杂场景下的鸟类检测数据集

写在前面&#xff1a;数据集对应应用场景&#xff0c;不同的应用场景有不同的检测难点以及对应改进方法&#xff0c;本系列整理汇总领域内的数据集&#xff0c;方便大家下载数据集&#xff0c;若无法下载可关注后私信领取。关注免费领取整理好的数据集资料&#xff01;今天分享…

一款可定时发圈和标签群发的微信管理软件是什么样的?

什么是时间管理&#xff1f;它是一种科学的解释&#xff0c;意味着时间的流逝是不可阻挡的&#xff0c;但是可以通过掌握时间来获取更多的改变。那如何在有限的生命里而做更多有意义的事情呢&#xff1f;学习一下时间管理&#xff0c;你一定会从中得到启发和答案的。 1.先确定…

MYSQL建库及查询

目的&#xff1a; 1.创建数据库&#xff0c;删除数据库&#xff0c;查询创建数据的语句&#xff0c;使用数据库&#xff0c;查询当前默认的数据库以及使用的编码方式校验规则 2.数字&#xff0c;文本&#xff0c;日期 在一章表中定义多个字段&#xff0c;要使用提到的所有的数…

vue 多环境打包指令配置及编译

1.创建多环境: 在根目录创建.env.xxx文件,如下为例(我创建了两个) 文件内容主要包括&#xff1a; # 页面标题 VUE_APP_TITLE "标题"# 生产环境配置 ENV production# DNA检测仓储管理系统/生产环境 VUE_APP_BASE_API https://xxxxxx 2.设置: 修改根目录下的package…

Parasoft Jtest 2023.1版本-全新的Jtest让你的Java测试更加容易

测试用例的创建和执行以及测量代码覆盖率是现代开发过程的重要组成部分。新发布的Parasoft Jtest 2023.1增加了重要的新功能&#xff0c;使Java开发和QA团队在测试实践中更具有生产力和效率。 通过使用最新版本的Jtest&#xff0c;您可以在Visual Studio code IDE中提高Java代…

设计模式之二:观察者模式

假定我们需要为Weather-O-Rama公司建立一个气象站系统&#xff0c;除已有的WeatherData有数据源类&#xff0c;还需要更新三个布告板的显示&#xff1a;目前状况&#xff08;温度、湿度、气压&#xff09;、气象统计和天气预报。 1 以下是一个可能的实现 class WeatherData { …

雅思口语备考模仿练习有没有用?

如何对于雅思口语进行模仿练习&#xff1f;这是很多同学需要了解的事情&#xff0c;那么接下来就和一起来了解一下雅思口语备考模仿练习有没有用&#xff1f; 模仿练习 1. 方法 众所周知&#xff0c;模仿最基本的方法便是跟读。跟读的途径可以是两种&#xff1a;一种是听录音…

【AcWing算法基础课】第四章 数学知识(未完待续)

文章目录 前言课前温习番外&#xff1a;秦九韶算法核心模板 一、质数1. 试除法判定质数核心模板1.1题目描述1.2思路分析1.3代码实现 2、试除法分解质因数核心模板1.4题目描述1.5思路分析1.6代码实现 二、筛素数1.朴素筛法求素数核心模板2.线性筛法求素数&#xff08;O(n)&#…

寻找nacos数据库连接名及密码

首先找到resources下的bootstrap.properties 找到其中的 spring.cloud.nacos.username***** spring.cloud.nacos.password**** 这个为nacos登陆的密码 到nacos中找到相应服务配置信息 spring.datasource.druid.urljdbc:mysql://ip地址 spring.datasource.druid.username用户…

防水防尘防震的工业三防平板电脑

工业三防平板电脑是一种具有防尘、防水和防震功能的平板电脑。它们被广泛应用于工业领域&#xff0c;特别是在恶劣环境下的工作场所。这些平板电脑具有坚固耐用的外壳和先进的技术&#xff0c;能够在恶劣的工作条件下提供稳定可靠的性能。 工业三防平板电脑的功能&#xff1a; …

Docker私有仓库搭建与界面化管理

一、关于Registry 官方的Docker hub是一个用于管理公共镜像的好地方&#xff0c;我们可以在上面找到我们想要的镜像&#xff0c;也可以把我们自己的镜像推送上去。 但是有时候我们的使用场景需要我们拥有一个私有的镜像仓库用于管理我们自己的镜像。这个可以通过开源软件Regi…

分享AIGC前沿论文系列二 面向区域级图像理解的端到端多模态大模型GPT4RoI

文章目录 概要论文摘要论文细节获取方式 概要 面向区域级图像理解的端到端多模态大模型 带来了超越图像级理解的全新对话和交互体验 进行丝滑的人机互动&#xff0c;不仅仅是文字级别的人机互动 论文摘要 本文提出对感兴趣区域进行Instruction Tuning&#xff0c;并提出GPT4…

Django基础入门⑬:Django表单实例【表单应用】获取全量书籍信息

Django基础入门⑫&#xff1a;Django 对象查询详解&#xff0c;分组聚合 Django表单实例表单应用编写模板层HTML页面编写视图层逻辑代码配置url路由模式映射页面搜索效果展示表单验证逻辑 获取全量书籍信息实现添加书籍信息 &#x1f3d8;️&#x1f3d8;️个人简介&#xff1a…