Cookie 和 Session

本文详细介绍了Cookie和Session在Web开发中的概念、工作原理、方法及示例,包括Cookie用于浏览器本地存储临时数据,Session在服务器端存储用户信息,以及它们在实现登录流程中的配合使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Cookie

1.1 概念

  1. 地位
    • Cookie 是浏览器在本地持久化存储“临时性数据”的一种机制。注意,说是存在浏览器,实际上是存在每一个网站上,且每一个网站都有对应的Cookie
    • 该数据其实只是在浏览器上暂时歇脚,真正起作用的是【把Cookie发给服务器,服务器根据不同的Cookie来执行不同的逻辑】的过程,即服务器的逻辑
  2. 存在的问题:Cookie可以伪造
  3. Cookie 的数据从哪来:由服务器返回给浏览器
  4. Cookie 数据的形式:由程序员自定义的键值对结构的数据
  5. Cookie 到哪里去:Cookie 的内容会在下次访问该网站时,自动地被带到HTTP请求中。这个请求被传输给服务器后,服务器就会根据里面的数据作出后续逻辑的实现。
  6. Cookie 如何存储
    • 存储结构:浏览器按照不同的“域名”分别存储Cookie。且域名与域名之间的Cookie是不能干扰的,不然会出现拿着A网站的SessionId访问到B网站的情况。
    • 存储位置:Cookie 是存储在硬盘上的,也正因如此,即使是电脑关机了,也依旧存在。
    • 超时时间:Cookie并非是可以一直存储的,是超时时间限制的,这可以保障网站的安全性。网站的安全性能要求越高,超时时间就越短
  7. 如何查看被存的Cookie:以edge浏览器为例子
    在这里插入图片描述
  8. Cookie 的基本工作过程
    • Cookie 由服务器通过调用一些API,往响应里面塞【set-Cookie】字段来添加。该字段里面会包含一些程序员自定义的键值对
    • 浏览器收到这样的键值对后,就会将其保存到本地,后续再给网站发送请求,就会把这些键值对自动带到请求的header里,不管此处服务是否需要该Cookie。

1.2 方法介绍

  1. 获取到请求中所有Cookie的内容 ----------> req.getCookies()
    返回值是一个数组,每个元素都是一个Cookie对象
  2. Cookie 类方法:
    • 获取 key:cookie.getName()
    • 获取 value:cookie.getValue
    • 设置 value:cookie.setvalue(String newValue)
  3. 把 Cookie添加到响应中:resp.addCookie(Cookie cookie)
    实际效果是在HTTP响应报文里加一个header名为【Set-Cookie】的键,要存储的Cookie就是里面的value。响应返回到浏览器这里,浏览器就可以保存这个Cookie了。

1.3 示例:设置 + 获取 Cookie

  1. 设置 Cookie
@WebServlet("/setcookie")
public class SetCookieServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //服务器返回两个自定义的Cookie给客户端
        Cookie cookie = new Cookie("username", "zhangsan");
        Cookie cookie1 = new Cookie("password", "123456");
        resp.addCookie(cookie);
        resp.addCookie(cookie1);
        resp.getWriter().write("setCookie ok");
    }
}

在这里插入图片描述

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

        resp.getWriter().write("ok");
    }
}

后续再次发送请求的时候,Cookie内容就会出现在请求中

在这里插入图片描述
在这里插入图片描述

二、Session

2.1 概念

  1. 地位:在服务器上存储了具体的自定义的信息

  2. 存在问题:分布式(部署在多个机器上)

    • 分布式 VS 单机
    • 问题解析
      • 企业开发中,一般对于一个服务至少会有2台机器以避免单点故障(一台机器挂了直接导致服务圈崩了)
      • 客户端发送的请求,会随机到一个服务器上。如果登录请求到了服务器A,A创建了Session,但是请求列表的请求到了服务器B,此时的服务器B并没有Session,提供不了服务
      • 我们做不到两台都存Session,因为登录请求只到了一台机器上。如果想要接收到的机器告诉其他机器,就需要根据“网络通信”知识,专门去实现了。
  3. Session对象形式:类似 Map<String, Object>

  4. 服务器如何组织 Session:服务器使用 Map 的方式来组织多个Session

    • 为什么要组织:因为每一个用户都应该有一个自己的Session + 一个服务器同时会有多个用户,所以一个服务器上会有很多份 Session
      在这里插入图片描述
  5. 名称:Session对象实际上也是键值对的格式,为了与key区分,Session对象叫【Attribute】

  6. SessionId VS JSESSIONID

    • SessionId 是一个广义的概念,在不同的库中具体实现过程会有一些细节上的差异
    • 在Servlet 里,把这个属性叫做【JSESSIONID】
  7. 特殊情况

    • SessionId还在,但是Session对象无了
      • 服务器是在内存上面存储Session对象和SessionId的的,但如果服务器重启了,内存中的这些会话数据就都无了。但是浏览器中的Cookie里的SessionId还是存在的。
      • 解决方法:为了解决上述问题,实践中直接不把 Session 保存在内存中,而是存储在其他能够实现“持久化存储”的介质上,如mysql、redis……
    • Session对象还在,但是SessionId无了:浏览器手动把Cookie删掉了

2.2 方法介绍

Servlet 提供了Session相关的操作,我们可以直接使用 Session 的API(封装了一些Cookie API的操作),而不是使用Cookie的API

  1. 获取Session:req.getSession()
    • 当参数为 true:一般在登录时使用
      (1)如果当前用户没有 Session(会话),就会创建Session
      (2)如果已经有了 Session,直接查询到Session
    • 当参数为 false:后续跳转到其他页面,检查用户的状态时使用
      (1)不存在Session(会话)返回null
      (2)存在Session直接查询
  2. gerSession() 原理介绍
    • (1)先读取请求中的 Cookie ,看Cookie里是否有SessionId(在Servlet下是【JSESSIONID】)
      • 如果没有,就认为需要创建新会话
      • 如果有,就拿着这个id去查询当前 Session 是否存在(获取Session对象)
        • 如果 Session 存在,直接返回该Session
        • 如果 Session 不存在,准备创建新会话
    • (2)如果当前确实需要创建会话,就会先创建出一个Session对象,同时生成一个唯一的JSESSIONID。并以【JSESSIONID】为key,Session对象为value,把这个键值对给插入到服务器上述的哈希表中
    • (3)刚才生成的JSESSIONID又会通过 “addCookie”加入响应中。此时响应里就会有“Set-Cookie”字段,这里的值就是【JSESSIONID=XXXX】,通过响应,就成功把JSESSIONID返回到浏览器了
  3. HttpSession 的方法
    • 根据名称获取对象:getAttribute(String name)
    • 设置对象:setAttribute(String name, Object value)

三、Cookie 和 Session联系

  1. 核心:Cookie 在浏览器上存储数据,Session则是在服务器上存储数据
  2. 工作过程
    • Session里存储的是用户的详细信息,同时会给用户分配一个唯一的身份标识,即SessionId。
    • Cookie 里面会存储SessionId。
    • 后续再访问该网站的其他页面时,请求就会自动带上SessionId,服务器根据这个确定是哪个用户在操作(找到该Id对应的详细信息),并给于对应服务
    • Session 里的键值对都是自定义的,可以不同
      在这里插入图片描述
  3. Cookie 和 Session 经常会在一起配合使用,但不是必须要一起使用
    • 我们可以用Cookie在客户端保存一些数据,这些数据不一定是用户身份信息,也不一定是SessionId
    • SessionId也不一定需要通过Cooke/Set-Cookie传递,比如通过URL传递

四、示例:通过Cookie和Session实现登录效果

4.1 前端页面

1. 当前页面是一个 form 表单,当用户点击【提交】按钮,就会发起一个HTTP请求
2. 该请求形如

<body>
    <form action="login" method="post">
        <input type="text" name="username">
        <input type="password" name="password">
        <input type="submit" name="登录">
    </form>
</body>

4.2 后端代码

@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");
        if (username == null || password == null || username.equals("") || password.equals("")){
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("请求的参数不完整");
            return;
        }

        //这里直接指定用户名一定要是zhangsan,密码一定要是123
        if (!username.equals("zhangsan")){
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("用户名错误!");
            return;
        }

        if (!password.equals("123")){
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("密码错误!");
            return;
        }

        //登录成功,给该用户创建会话
        HttpSession session = req.getSession(true);
        session.setAttribute("username", username);
        session.setAttribute("time", System.currentTimeMillis());

        resp.sendRedirect("index");
    }
}
@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");
        Long time = (Long)session.getAttribute("time");
        System.out.println("username=" + username + ", time=" + time);

        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write("欢迎您, " + username + ", 上次登录时间:" + time);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值