浅谈 Cookie 和 Session

理解Cookie

在前面的 HTTP 协议中,也理解过这个 Cookie,HTTP 协议自身是属于 “无状态” 协议.

"无状态" 的含义指的是: 默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系.

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

例如在我们登录网站成功后,在我们第二次去访问的时候服务器就能够知道这个请求是否已经登录过了…

在这里插入图片描述

在这里插入图片描述

上面的令牌通常就是存储在 Cookie 字段中…

谈到在 HTTP协议中的例子:
1: 我们先到医院去挂号,挂号的时候提供身份证,同时得到一张"就诊卡",里面存身份信息,就相当于"令牌"
2: 后面去看病的时候,不管走到那个科室(眼科,鼻科,抓药…)就不需要在把身份证拿出来了,直接拿出就诊卡就可以识别你的身份了
3: 不想要这张卡了,那我们也可以注销这张卡,此时,里面的身份信息,诊断信息就销毁了
4: 又来这个医院看病,可以重新办一张,就又有一个新的"就诊卡了"

理解Session

就诊卡里面存储的就诊信息,就是在 Session(处在服务器) 中存储了
Session叫做会话,因为我们服务器在同一时刻收到的请求是很多的,服务器他就要区分哪个请求是哪个用户的,就是通过这个"令牌来确认关系".

核心方法

HttpServletRequest 类中的相关方法:

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

getSession 方法,既能用于获取到服务器上的会话,也能用于创建会话:
如果参数为 true:会话不存在,则会创建会话,如果会话存在,就会获取
如果参数为false:会话不存在,直接返回 null,会话存在,才会获取

举个例子:
来到一家新医院,先挂号获取到"就诊卡",人家挂号的医生就会问你,你有没有这里的"就诊卡",有就不需要在办了,如果没有,就需要办一张,挂号之后,你就会有一张"就诊卡",同时的医院也会给你开一个档案来存储你的就诊信息(这就是会话),如果这个医院人流量特别多,那这个医院的承载病人的能力是有上限的,这个时候医生就会问你在这里建过档没有,如果建过,才会给你挂号,没有建过的话就不给你挂(就像生娃的时候得提前预约,提前来建个档,因为妇产科人是特别多的,没预约的话,很难挂上号)

在调用 getSession的时候我们还要:

1:创建会话:
首先就是要先获取到请求中 Cookie 里面的 sessionId字段(相当于会话的身份标识),判定这个 sessionId 是否在当前服务器上存在,如果不存在,就会进入到创建会话的逻辑

创建会话,就会创建一个 HttpSession 对象,并且生成一个 sessionId(这个sessionId 是一个很长的数字,通常是用十六进制来表示,能够保证唯一性.),接下来就会把这个 sessionId 作为 key,把这个 Httpsession 对象,作为 value,把这个键值对,给保存到服务器内存的一个"哈希表"(也不一定是他,只是类似这种结构)这样的结构中,再然后服务器就会返回一个 HTTP 响应,把 sessionId 通过 Set-Cookie 字段返回给浏览器,浏览器就可以保存这个 sessionId 到 Cookie 中了,例如,登录gitee
在这里插入图片描述

2: 获取会话:
先获取到请求中的 Cookie 里面的 sessionId字段(会话的身份标识),判定这个sessionId 是否在当前服务器上存在(也就是在 哈希表 中是否存在),如果有,就直接查询出这个 HttpSession 对象,并且通过返回值返回回去

HTTP 请求中的 Cookie 字段就是按照键值对的方式来组织的,这里的这些键值对,大概的格式是使用 ; 来分割键值对,使用 = 来分割键和值,这些键值对都会在请求中通过 Cookie 字段传给服务器,服务器收到请求后,就会进行解析,解析成 Cookie[] 这样的形式

HttpServletResponse 类中的相关方法:

方法 描述
void addCookie(Cookie cookie) 把指定的 Cookie 添加到响应中

响应中就可以根据 addCookie 这个方法来添加一个 Cookie 信息到响应报文中,这里添加进来的键值对,就会作为 HTTP 响应中的 Set-Cookie 字段来表示

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

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

HttpSession 对象:
这个对象本质上也是一个"键值对"的结构.允许程序员往 HttpSession 对象中,存取任意键值对数据.(但是 key 必须是String,value是一个 Object)
在这里插入图片描述

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

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

案例-网页登录

流程:
在这里插入图片描述
约定的前后端交互接口:
在这里插入图片描述

1. 编写一个简单的登录页面

使用 form表单来构造 post 请求:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>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>

2. 编写一个 Servlet 来处理这个登录请求

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 处理用户请求
        String userName = req.getParameter("userName");
        String passWord = req.getParameter("passWord");
        // 判定用户名或者密码是否正确~~
        // 正常来说这个判定操作是要放到数据库中进行存取的.
        // 此处为了简单, 就直接在代码里写死了. 假设有效的用户名和密码是 "zhangsan", "123"
        if ("zhangsan".equals(userName) && "123".equals(passWord)) {
    
    
            // 登录成功!
            // 创建会话, 并保存必要的身份信息.
            HttpSession httpSession = req.getSession(true);
            // 往会话中存储键值对. 必要的身份信息
            httpSession.setAttribute("username", userName);
            // 初始情况下, 把登录次数设为 0
            httpSession.setAttribute("count", 0);
            resp.sendRedirect("index");
        } else {
    
    
            // 登录失败!
            resp.getWriter().write("login failed!");
        }
    }
}

3. 编写服务器返回主页的逻辑

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/index")
public class IndexServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 返回一个主页. (主页就是一个简单的 html 片段)
        // 此处需要得到用户名是啥, 从 HttpSession 中就能拿到.
        // 此处 getSession 的参数必须是 false. 前面在登录过程中, 已经创建过会话了. 此处是要直接获取到之前的会话.
        HttpSession session = req.getSession(false);
        String username = (String) session.getAttribute("username");
        // 还从会话中取出 count.
        Integer count = (Integer) session.getAttribute("count");
        count += 1;
        // 把自增之后的值写回到会话中.
        session.setAttribute("count", count);

        resp.setContentType("text/html;charset=utf8");
        resp.getWriter().write("<h3>欢迎你! " + username + " 这是第 " + count + " 次访问主页 </h3>");
    }
}

4. 启动服务器验证

第一次交互:浏览器从服务器上拿到登录页面:
第二次交互:点击登录之后,就会给服务器发送一个登录请求,服务器就会响应
在这里插入图片描述在这里插入图片描述
第三次交互:浏览器收到 302 响应之后,再次向服务器发起请求,来访问主页
在这里插入图片描述

在这里插入图片描述

Cookie 和 Session 区别

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

猜你喜欢

转载自blog.csdn.net/chenbaifan/article/details/124940174