Cookie 和 Session

x33g5p2x  于2022-05-05 转载在 其他  
字(5.9k)|赞(0)|评价(0)|浏览(253)

因为HTTP是无状态的协议,无法根据之前的状态进行本次的请求处理
为了保留无状态协议这个特征,于是引入了 Cookie 信息来控制客户端的状态.
Cookie会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的首部字段信息,通知客户端保存 Cookie.当下次再给该服务器发送请求的时候,客户端会自动在请求报文中加入Cookie值后发送出去.
服务器端发现客户端发送来的 Cookie 后,会去检查是哪一个客户端发来的连接请求,对比服务器上的记录,最后得到之前的状态信息.

此时在服务器这边就需要记录Cookie信息, 这个就是 Session 机制所做的工作

2. 什么是 Session

Session 译为 会话 .Session是存储在服务端的,当客户端第一次访问服务端的时候,服务端会把客户端的信息存储在服务器上,当客户端再次访问的时候,就可以通过 Session中查找该客户端的状态就可以了.存储的方式类似于 哈希表.

  1. Cookie 是保存在 客户端, Session 是保存在 服务端
  2. Cookie 不安全
  3. 单个Cookie保存的数据不能超过 4k
  4. CookieSession 经常会在一起配合使用. 但是不是必须配合

4. 相关方法

HttpServletRequest 类中的相关方法

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

HttpServletResponse 类中的相关方法

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

HttpSession 类中的相关方法

方法描述
Object getAttribute(String name)该方法返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null.
void setAttribute(String name, Object value)该方法使用指定的名称绑定一个对象到该 session 会话
boolean isNew()判定当前是否是新创建出的会话
方法描述
String getName()该方法返回 cookie 的名称。名称在创建后不能改变。(这个值是 SetCooke 字段设置给浏览器的)
String getValue()该方法获取与 cookie 关联的值
void setValue(String newValue)该方法设置与 cookie 关联的值。

注意事项

  • 通过 HttpServletRequest.getCookies() 获取到请求中的一系列 Cookie 键值对.需要带有参数
    当为 true 的时候, 如果 session 不存在,就会创建,如果存在,就获取session然后返回
    当为 false 的时候,如果 session 不存在,就会返回null,如果存在,就获取session然后返回
  • HTTP 的 Cooke 字段中存储的实际上是多组键值对. 每个键值对在 Servlet 中都对应了一个 Cookie对象.Cookie里主要有 keyvalue 两个属性

5. 实现一个用户登录

① 创建 maven 项目,引入需要的库和目录

创建 webapp/WEB-INF/web.xml

web.xml

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>

引入 Servlet

② 首先设计好前端后端交互接口

客户端给服务器第一次交互, 登录请求
登录账号,之后重定向到第二次交互

此时重定向到第二次交互,访问主页

③ 写 login.html (登录页面)

login.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="css/common.css">
  <link rel="stylesheet" href="css/login.css">
</head>
<body>
    <div id="leader">
      <div class="login">
        <form action="login" method="POST">
          <div class="title">某某管理系统</div>
          <div class="one"><input type="text" name="username" class="user"><input type="password" name="password" class="password"></div>
          <div class="submit"><button>登 录</button></div>
        </form>
      </div>
    </div>
</body>
</html>

common.css

* {
    padding: 0;
    margin: 0;
}
html,body {
    width: 100%;
    height: 100%;
}

login.css

#leader{
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
}

.login {
    background-color: pink;
    width: 400px;
    height: 290px;
    padding: 25px;
    border-radius: 10px;
}
.login .title{
    font-size: 30px;
    font-weight: 600;
    text-align: center;
    margin: 5px;
}
.login .one{
    display: flex;
    flex-direction: column;
    align-items: center;
}
.login .user,.login .password {
    width: 380px;
    height: 35px;
    margin: 10px;
    border-radius: 8px;
    padding: 5px;
    border: none;
}
.login .submit{
    margin: 10px;
}
.login .submit button{
    display: block;
    margin: 0 auto;
    width: 100px;
    height: 50px;
    background-color: orange;
    color: white;
    border-radius: 5px;
    border: 0;
}
.login .submit button:active{
    background-color: red;
}

④ 写 LoginServlet

这里是账号密码是直接固定好了

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 {
        resp.setContentType("text/html;charset=utf-8");
        // 1. 先从请求的body中读取 用户名 和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        // 2. 判定 用户名密码 是否正确(这里直接固定)
        if(!"wz".equals(username) || !"123456".equals(password)){
            // 用户名和密码有错误的
            resp.getWriter().write("登录失败!");
            return;
        }
        // 3. 登录成功,则创建一个会话出来.
        HttpSession httpSession = req.getSession(true);
        httpSession.setAttribute("username","wz");
        httpSession.setAttribute("loginCount",0);
        // 4. 让页面跳转到主页,使用重定向
        resp.sendRedirect("index");
    }
}

⑤ 写 IndexServlet

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 {
        // 根据当前用户请求中的 sessionId, 获取到用户信息,并显示到页面上
        resp.setContentType("text/html;charset=utf-8");
        // 1. 判定当前用户是否已经登录了.
        HttpSession httpSession = req.getSession(false);//这里如果不存在就不需要创建.
        if(httpSession == null){
            resp.sendRedirect("login.html");
            return;
        }
        // 2. 如果已经登录,就可以从 HttpSession 中拿到用户信息了
        String username = (String) (httpSession.getAttribute("username"));
        Integer loginCount =  (Integer) (httpSession.getAttribute("loginCount"));
        loginCount = loginCount + 1;
        httpSession.setAttribute("loginCount",loginCount);
        // 3. 返回一个 HTML 页面
        StringBuilder html = new StringBuilder();
        html.append("<div>用户: "+username+"</div>");
        html.append("<div>访问次数: "+loginCount+"</div>");
        resp.getWriter().write(html.toString());
    }
}

运行结果

首先浏览器输入 http://127.0.0.1:8080/ForLogin/login.html

输入 "wz" "123456"

在刷新页面的时候,会增加访问次数

查看抓包结果

第一次交互的请求

第一次交互的响应

第二次交互的请求

第二次交互的响应

相关文章