经典面试题:理解Cookie和Session之间的区别-1

简介: 经典面试题:理解Cookie和Session之间的区别

一、Cookie概念先知

1、Cookie是什么?

对于Cookie来说,它是HTTP报文header头部中非常重要的一个属性,是浏览器提供给网页访问本地数据用的

💬 那此时就有同学疑惑了,难道浏览器可以随机地访问本地磁盘吗?这不是很危险?

  • 这确实很危险,于是就规定了网页在打开的时候无法去访问本地的磁盘,否则用户打开一些恶意网站时就会造成磁盘数据被破坏的情况,那浏览器要如何去保存用户的信息呢?
  • 此时就需要使用到Cookie了,网页提供了一种机制,使得网页可以通过Cookie去获取到用户的相关信息,但是不可以去直接访问用户的本地磁盘

所以总的来说,Cookie是浏览器提供的持久化存储数据的机制

2、Cookie从哪里来?

  • Cookie中的数据来自于服务器,服务器会通过HTTP响应的报头部分(set-Cookie字段),来决定要把啥样的信息保存到客户端这边去, 以及决定浏览器的Cookie要存什么~
  • 通过HTTP响应的Set-Cookie字段,把键值对写回去即可

3、Cookie要存到哪里去?

最后要回到服务器这里,Cookie会在后续浏览器访问服务器的时候带回请求的header中发给服务器

💬 有同学问了,为什么要这么折腾呢?这样来回陶腾?

  • 原因是服务器不是只给一个客户端提供服务,同一时刻要处理多个客户端,此时服务器就可以通过Cookie中的值来识别当前客户端是谁,当前客户端的服务提供到哪个环节了(客户端借助Cookie自报家门
  • 客户端这边会通过Cookie来保存当前用户使用的中间状态,当客户端访问浏览器的时候,就自动得把Cookie的内容带入到 请求(request) 中,此时服务器就能够知道现在客户端是什么样子了

4、Cookie是存在哪里的?

可以认为是存在于浏览器中的,存在于硬盘里的

  • Cookie在存的时候,是按照浏览器 + 域名的维度来进行细分的,不同的浏览器有各自的Cookie,同一个浏览器不同的域名,对应不同的cookie。例如同一张网页,Google浏览器和火狐浏览器的Cookie都是不同的🌏

5、浏览器是如何通过Cookie来记录的?

  • 当浏览器保存好Cookie后,再给服务器发送请求的时候,就会带上之前所存在的Cookie,它就像服务器在浏览器这边搞的寄存器一样,拥有一定的【记忆存储功能】
  • 但和保存聊天记录又是不同的概念,而且浏览器中的保存账号密码和http没有多大联系

6、Cookie的过期时间有什么用?

Cookie里面的内容不光是键值对,同时还有过期时间,到一定时间就会自动过期

  • 有些公共的电脑,比如学校图书馆中的电子阅览室中的那些,在这些电脑上可以登录自己的账号,然后登录状态就会保存到Cookie中了
  • 但是在下次再来使用的时候,Cookie可能就过期了,就需要重新登录,越是敏感(和钱相关)的网站,过期时间就越短,道理很简单,如果你在一台公共电脑中登录了自己的淘宝账号去买东西,在你下机之后另一个人也可以继续使用你的账号,此时就会变得非常危险

二、见见Cookie

了解了Cookie的基本概念后,我们来见见Cookie

  • 例如我现在打开CSDN的这个网站,然后点击网址中的🔒,就可以看到我这个浏览器中的一些Cookie值了

image.png

  • 接着继续点击去,就可以看到在Cookie存放的一些具体内容,也就是我在登录一些网站之后所留下的一些个人信息

image.png

除了可以直接在浏览器中找到Cookie,而且可以看到里面存放的用户信息,但是具体的内容是什么呢?这些是可以由我们程序员来自定义的。这样,我们通过抓包来看看👈

  • 通过抓包可以看出,header头部中的Cookie所保存的内容是一堆很奇怪的内容,具体这些内容所代码的含义是什么呢?这个我也不知道,上面说过了,这是由程序员来自定义的,这一块可以在我后面介绍了HttpSession后再做深入,这里了解一下即可

image.png

三、会话机制Session

知道了什么是Cookie,接下去我们来说说会话机制Session,它又是个什么东西呢?

  • 服务器同一时刻收到的请求是很多的. 服务器需要清除的区分清楚每个请求是从属于哪个用户, 就需要在 服务器这边记录每个用户【令牌】以及用户的信息的对应关系
  • 具体地可以先看看下面这张图,当一个客户端去访问服务器的时候,就会带有一个【token】,我们也把它称作为sessionId,是服务器这边分配给每一个用户的,当服务器这边保存了每个用户的相关信息后,下次再登录的时候就不需要再输入用户名和密码,服务器只需要根据这个id去进行查询即可

image.png

  • 可以看到,当用户登陆的时候, 服务器在 Session 中新增一个新记录, 并把 sessionId / token 返回给客户端. (例如通过 HTTP 响应中的 Set-Cookie 字段返回)
  • 客户端后续再给服务器发送请求的时候, 需要在请求中带上 sessionId/ token. (例如通过 HTTP 请求 中的 Cookie 字段带上)
  • 服务器收到请求之后, 根据请求中的 sessionId / token 在 Session 信息中获取到对应的用户信息, 再进行后续操作
  • 上面的这些sessionId和每个用户的信息构成一个键值对,用户的信息又单独构成一个键值对,例如:姓名是什么、年龄是什么、账户余额是什么?

💬 可能在看了上面这些后你对会话Sesion还不是很了解,不过没关系,后面我在使用代码讲解用户登录的时候就会一目了然了~

四、理解Cookie和Session的区别【⭐】

接下去我们来看看Cookie和Session之间的区别

  1. Cookie是客户端的存储机制,Session是服务器的存储机制
  2. Cookie里面可以存各种键值对(还可以存别的);Session则专门用来保存用户信息
  3. Cookie完全可以单独使用,不搭配Session(实现非 登录 场景下);Session也可以不搭配Cookie使用.(手机app登录服务器,服务器也需要Session,此时就没有Cookie的概念),Cookie跟浏览器强相关的~
  4. Cookie 是属于HTTP协议中的一个部分,Session 则可以和HTTP无关(TCP、websocket...也可以用session)

💬 上面的这些,你可以认为是大家口中所述的 “八股文”,但是光这么背一定没什么效果的,主要在于理解,在理解了Cookie和Session的交互机制后再来看这些东西你会发现根本不需要背

五、核心方法介绍

然后我们来讲一下后面再模拟实现Cookie和Session机制时的一些核心方法,也就是我们所说的API

HttpServletRequest 类中的相关方法

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

HttpServletResponse 类中的相关方法

方法 描述
void addCookie(Cookie cookie) 把指定的 cookie 添加到响应中
void sendRedirect(String location) 使用指定的重定向位置 URL 发送临时重定向响应到客户端

HttpSession 类中的相关方法

一个 HttpSession 对象里面包含多个键值对. 我们可以往 HttpSession 中==存任何我们需要的信息==

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

Cookie 类中的相关方法

每个 Cookie 对象就是一个键值对

方法 描述
String getName() 该方法返回 cookie 的名称。名称在创建后不能改变。(这个值是 Set-Cooke 字段设置给浏览器的)
String getValue() 该方法获取与 cookie 关联的值
void setValue(StringnewValue) 该方法设置与 cookie 关联的值

💬 上面的这些方法,我们在下面进行【用户登录】的时候会用到三四个,不需要全部都记住

六、实现用户登录【✔】

1、淘宝用户登录原理解说

  • 对于淘宝相信很多同学都用过,可以在上面买一些东西,但是你知道我们在访问淘宝页面的时候是如何与后端的服务器进行交互的吗?

image.png

这里我画了一张交互图,可以通过这张图来分析浏览器页面与淘宝后端服务器的这个交互过程

  1. 首先当我们浏览器点击淘宝主页链接的时候,我们就可以看到这个主页的样子,此时就是与服务器进行的第一次交互,即发送了一个GET请求去获取到当前的这个HTML页面,接着服务器收到这个请求后就将淘宝的主页展示给我们,==不过此时服务器是不知道我们的身份信息的==
  2. 第二次交互就是在我们进行登录的时候了,此时我们点击网页中的【登录】按钮输入自己的用户名和密码,你可以认为这是一个表单,那此时我们发起的就是一个POST请求,此时当服务器接收到这个请求后获取到用户输入的这些信息,进行一个校验和判断,若是用户输入的信息正确的话(已经注册过),此时服务器就会生成一个sessionId,将此id封装在HTTP响应报文中进行返回,并且在自己这里新建一个会话Session去保存用户的相关信息,后续服务器只需要通过这个sessionId去进行判断即可
  3. 当服务器返回登录成功的提示信息给到用户后,浏览器这边也会同时将服务器存放在响应报文中的SessionId / token存放在【Cookie】中,这也就是为什么我们的Cookie中为什么可以保存这么多东西了
  4. 但是淘宝不仅仅只有一个主页,而是由多个页面所构成的,所以当用户在访问淘宝的其他页面时间,又会向服务器发送请求,此时是GET请求服务器再收到请求后进行判断当前这个用户是否已经登录过,通过获取到当前用户所携带的sessionId进行判断,当前若是这个id == null的话表示当前用户还未登录,需要先去进行一个登录;如果已经登录过的话就会相关的网页显示给用户

image.png

  • 上述的这么一个交互过程,就是Cookie和Sessiond的这么一个交互逻辑,服务器通过给每一个登录进来的用户创建一个新的会话,并且为其分配一个身份的序号,将其作为key值,那么这个用户相对应的信息就作为value值,你可以把它看作是一个【哈希表】的结构,存放的都是一个个键值对
  • 每一个会话都是一个键值对,会话中每个用户的相关信息又是一个键值对,是一个HttpSession对象。在后续的请求中的,服务器收到相关的Cookie中的身份序号,就会根据这个序号去查询上述的哈希表,来判断是哪一位用户。如果查到了,就知道当前用户是谁,无需再重新输入密码,增加了效率也方便了用户

💬 可能你还不懂什么是HttpSession对象,下面我会通过一个例子去进行陈述

2、模拟实现服务器响应用户登录请求

需求分析

首先来讲一下这个模拟实现前后端需要分别准备的工作

① 前端:一个登录页面,一个主页面

② 后端;两个Servlet,一个是处理登录的loginServler,判断输入的用户名或密码是否正确;另一个是构造主页面的indexServlet

  • 首先的话是供用户输入信息的表单,用于向服务器发送POST请求
<form action="login" method="post">
    <label>用户名:</label>
    <input type="text" name="userName"><p></p>
    <label>密码:</label>
    <input type="text" name="passWord"><p></p>
    <input type="submit" value="登录">
</form>

接下去是后端的这一块登录逻辑,主要来分析一下这里

  • 首先的话是要获取到用户输入的内容信息
String userName = req.getParameter("userName");
String passWord = req.getParameter("passWord");

然后便是去进行相关的逻辑判断,看看输入的信息是否合法,这边我给出了两种写法,第一种写法比较直观易懂一些,就是使用逻辑或||去做一个判断,但是我平常在写代码逻辑的时候一般都是以第二种写法,防止产生if的嵌套

        /**
         * 判断用户输入的用户名和密码是否正确
         */
//        if(useName.equals("zhangsan") || passWord.equals("lisi")){
//            if(passWord.equals("123456")){
//                // 登录成功
//            }else{
//                // 登录失败
//            }
//        }else{
//            // 登录失败
//        }
if(!userName.equals("zhangsan") && !userName.equals("lisi")){
    // 登录失败
    // 1.打印日志
    System.out.println("用户名错误");
    // 2.重定向
    resp.sendRedirect("login.html");
    return;
}
if(!passWord.equals("123456")){
    // 登录失败
    // 1.打印日志
    System.out.println("密码错误");
    // 2.重定向
    resp.sendRedirect("login.html");
    return;
}
  • 这个sendRedirect()就是我们在上面介绍到的HttpServletResponse中的一个方法,用于去进行一个【重定向】的操作,使用户名或者密码输入错误的用户回到登录页面继续输入
resp.sendRedirect("login.html");
  • 如果上述条件都不满足的话代表就是登录成功,此时在服务端这边就会为当前用户创建一个SessionId,以返回给用户做下一次的校验。
  • 并且还会在自己这里为当前用户创建一个会话,这里用到了HttpServletRequest中的 getSession()方法,可以看到我为其传入了一个参数为【true】,代表若是这个SessionId存在的话就会返回一个HttpSession的对象,此时我们就可以手动地为这个对象去设置参数,那就是使用到 HttpSession 中的setAttribute()方法,所以说这里面的东西可以由我们程序员来进行自定义
// 登录成功
// 1.创建一个会话【所谓的会话就是一个键值对, key是sessionId, value是HttpSession对象】
HttpSession httpSession = req.getSession(true);
// 2.将当前登录的用户名保存到会话中,HttpSession所构建对象的value值也是一个 map 结构
httpSession.setAttribute("userName", userName);
httpSession.setAttribute("passWord", passWord);
httpSession.setAttribute("loginCount", "0");

因为这一块涉及键值对的嵌套,比较难理解一些,读者可以通过这张图来帮助理解,每个会话即对应一个客户端,而且它是一个键值对的形式,SessionId为【key】,HttpSession为【value】,而且其内部保存用户的信息也是一个键值对的形式,可以由我们程序员来自己定义

image.png

// 3.重定向到主页
resp.sendRedirect("index")

👉 最后的这一句要和indexServlet这个类合起来说,因为此时已经为用户创建好了一个会话,此时当前的这个loginServlet的工作已经做完了,接下去我们要模拟的就是用户拥有这个SessionId后去进行登录时与服务器产生的第二次交互。当然这里你可以去再实现一个页面然后重定向到这个页面,这边我就直接通过@WebServlet注解去进行一个转交了

@WebServlet("/index")
  • 然后便是这一块的逻辑,如果用户一开始在访问主页的时候没有进行过登录,那此时他是不会有这个SessionId的,那便需要用户先去进行一个登录的操作,可以看到这边的getSession()我传入的false,此时就不会去新建一个会话,而是直接返回null,我们便可以根据这个来判断,打印日志并回到登录页面让用户先行登录
  • 若是用户已经登录的话表明服务器获取到它的SessionId了,==那就表明当前用户之前已经登录过==,此时我们要执行的逻辑就是去构造一个http界面然后欢迎用户,不过在这之前你一定发现我多做了一些事,那就是设置了一个loginCount,在每次判定当前用户确实存在时,就取出这个loginCount,不过我们是以字符串的形式存放进去的,那么拿出来的话进行计算的话就要用整数的形式进行操作,所以这边用到了一个Integer.parseInt(),每次当前用户登录进此页面的时候它的访问此处就 + 1
  • 最后的话我们再将当前用户的相关信息构建成一个HTML页面显示在浏览器上,注意这个页面是我们自己构造出来返回给用户的,而不是早已经有的
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setContentType("text/html;charset=utf-8");
    HttpSession httpSession = req.getSession(false);
    // 1.首先根据用户名判断当前用户是否登录过
    if(httpSession == null){
        // 说明该用户还未登录,提示登录
        System.out.println("您还未登录,请重新登录");
        resp.sendRedirect("login.html");
        return;
    }
    // 2.表明用户登录过,根据根据sessionId,显示欢迎界面
    String userName = (String)httpSession.getAttribute("userName");
    String CountString = (String)httpSession.getAttribute("loginCount");
    int loginCount = Integer.parseInt(CountString);
    loginCount += 1;
    httpSession.setAttribute("loginCount", loginCount + "");
    // 构造页面
    StringBuilder html = new StringBuilder();
    html.append(String.format("<div>用户名:%s</div>", userName));
    html.append(String.format("<div>登录次数:%d</div>", loginCount));
    resp.getWriter().write(html.toString());
}
相关文章
|
14天前
|
存储 JavaScript 前端开发
学习vuex和localstorage . cookie的作用与区别
探讨Vuex、LocalStorage与Cookie:三种关键技术在现代Web开发中的角色。Vuex作为Vue的状态管理工具,提供集中、响应式且可预测的状态变更机制,适用于复杂应用。LocalStorage为客户端提供大容量、持久化的数据存储方案,适合保存用户偏好等静态信息。Cookie则擅长会话跟踪与认证管理,数据虽小却能在客户端与服务器间传递。每种技术针对不同场景各有优势,合理选用是关键。
|
6天前
|
存储 NoSQL Java
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这篇文章是关于Java面试中的分布式架构问题的笔记,包括分布式架构下的Session共享方案、RPC和RMI的理解、分布式ID生成方案、分布式锁解决方案以及分布式事务解决方案。
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
|
7天前
|
存储 JSON JavaScript
震撼!Cookie、Session、Token、JWT 终极对决:揭开 Web 认证的神秘面纱!
【8月更文挑战第13天】Web 开发中,Cookie、Session、Token 和 JWT 常混淆。Cookie 是服务器给客户端的小信息片,如登录状态,每次请求都会返回。Session 则是服务器存储的用户数据,通过 Session ID 追踪。Token 类似通行证,证明客户端身份且可加密。JWT 是结构化的 Token,含头部、载荷及签名,确保数据完整性和安全性。
19 4
|
22天前
|
存储 安全 搜索推荐
Cookie和Session的区别,99%的程序员都不知道的细节!
大家好,我是小米,在Web开发中,Cookie和Session是两种重要的状态管理工具。它们有着不同的存储位置、安全性和应用场景。本篇文章将详细解析它们的区别和应用,让你在开发过程中能够更加游刃有余。让我们一起深入了解吧!
36 1
|
8天前
Error unprotecting the session cookie.The key {...} was not found in the key ring.
Error unprotecting the session cookie.The key {...} was not found in the key ring.
18 0
|
8天前
Error unprotecting the session cookie.The payload was invalid.
Error unprotecting the session cookie.The payload was invalid.
23 0
|
4天前
|
存储 缓存 网络协议
复盘女朋友面试4个月的Java基础题
这篇文章是关于Java基础面试题的复盘,涵盖了HashMap原理、对象序列化作用等高频面试问题,并强调了Java基础知识的重要性。
复盘女朋友面试4个月的Java基础题
|
29天前
|
SQL Java Unix
Android经典面试题之Java中获取时间戳的方式有哪些?有什么区别?
在Java中获取时间戳有多种方式,包括`System.currentTimeMillis()`(毫秒级,适用于日志和计时)、`System.nanoTime()`(纳秒级,高精度计时)、`Instant.now().toEpochMilli()`(毫秒级,ISO-8601标准)和`Instant.now().getEpochSecond()`(秒级)。`Timestamp.valueOf(LocalDateTime.now()).getTime()`适用于数据库操作。选择方法取决于精度、用途和时间起点的需求。
32 3
|
1月前
|
存储 算法 Java
Java面试之SpringCloud篇
Java面试之SpringCloud篇
67 1
|
1月前
|
SQL 关系型数据库 MySQL
java面试之MySQL数据库篇
java面试之MySQL数据库篇
35 0
java面试之MySQL数据库篇