Cookie 和 Session

哥几个来学 Cookie 和 Session 啦~~

目录

🌲 一、Cookie 

🌳二、Session (会话)

🌴三、Cookie 和 Session 的区别

🌵四、实现一个简单的登录功能

🥗核心方法:

🥙前端页面:

🥪后端代码:

🍧账号密码校验的Servlet:

🍨生成主页的 Servlet:


 

 🌲 一、Cookie 

        Cookie 直接翻译称为:曲奇饼。但是在网络上可与这种 小甜饼干 没有半毛钱关系~~

        Cookie 中存储了一个字符串,这个数据可能是客户端(网页)自行通过 JS 写入的,也可能来自于服务器( 服务器在 HTTP 响应的 header 中通过 Set-Cookie 字段给浏览器返回数据 )

 Cookie 的值也是由键值对组成的:

键与值之间用“=”分隔;键值对之间用“;”分隔。

这里的键值对是由程序员规定的,不同的网站有不同的 键值对,也就有不同的含义和用途。

Cookie 的本质:

是浏览器在本地存储 用户自定义数据 的一种关键机制。

就拿最典型的 登录操作 举例:

假设我们要登陆 B站,我们输入 账号 和 密码 之后点击登录

登陆成功:

当我们关掉 这个 B站 的页面之后

然后再次 打开我们心爱的 B站 

我们发现:并不需要重新登录,我们的浏览器已经帮我们“登录”好了。 

实现这种效果离不开我们的 Cookie~~

从上述流程我们不难了解:

Cookie 从哪来?

Cookie 从服务器来。当我们的浏览器访问服务器的时候,服务器就会在 HTTP 响应中,通过 Set-Cookie 字段,把 Cookie 的键值对返回给浏览器。

Cookie 到哪去?

浏览器会在下一次请求的时候,把 Cookie 带给服务器,Cookie 在浏览器这边,只能算是 “暂存” ,真正要让这个数据发挥作用,还得是由服务器来使用。

Cookie 有什么用?

Cookie 是浏览器本地存储数据的机制。存的不一定是账户信息,想存任何东西都可以(前提是得是字符串)。由于 Cookie 的存储空间有限,一般不会用 Cookie 存储太大的数据~~

上面我们提到 Cookie 是浏览器本地存储数据的机制。既然涉及到存储,那么具体怎么个存法呢?

是不是直接存储到硬盘文件上就行了呢?

万万使不得!!

        这个操作无异于允许网页直接操作你电脑的文件系统,那么如果你一旦不小心点到了一个奇奇怪怪的网站,那么你的电脑可能就会被这些恶意网站的开发者给 “夺舍了”。

        因此,为了保证用户上网能够比较安全,浏览器会作出限制,禁止网页能够直接访问硬盘。

        虽然浏览器禁止了直接访问硬盘,但是允许网页往浏览器这里存储一些 Cookie ,这些数据通过浏览器提供的 api,写入特定的文件中。

        由于网页由很多很多个,因此每个网站都是存自己的 Cookie (按照域名为维度来进行存储)。

        比如同一个网站(B站的舞蹈区、影视区、动画区等)共享一份 Cookie 。而不同的网站(百度、搜狗、B站等)是各有各的 Cookie 。

除了 浏览器禁止网页能够直接访问硬盘 之外,还有一种机制能够防止 Cookie 信息泄漏,那就是

Session (会话)
 

🌳二、Session (会话)

首先引入概念,什么是Session (会话)?

Session (会话)就是服务器这边用于区分用户身份的一种机制,通常是配合cookie来使用的。

会话的本质就是一个哈希表,存储了一些键值对结构,key就是令牌的ID(Session Id),value就是用户的信息,这个用户信息可以可以根据需求灵活设计。

也就是说,Session (会话) 可以通过 Session Id 从 哈希表 中找到用户信息,从而来判断这个用户是谁~~

Session (会话)的开始时间:

浏览器访问服务器的时候就是会话的开始。

Session (会话)的结束时间:

        会话的关闭时间比较模糊,当你关掉浏览器的时候并不代表会话结束,不同的网站对于每个用户的会话都设定了确定的 结束会话的时间唯一的 Id

这里的 “唯一的 Id” 通常指的是 Session Id

这个 Session Id 是 服务器 产生的东西,所以一般都会保存在 数据库 中

注意:这个 Session Id 也可以叫 token(同一事物的不同叫法)

那么问题来了,为什么有了用户名还需要使用 Session Id ?

我们再来演示一下 B站 的登录流程,这次加上 Session(会话)的机制:

 由于在 第步 的时候,Cookie 没有保存 账号密码,而是保存了 在 第步 已经加到 Cookie 里的 Session Id。而这个 Session Id 是一个 无规律的 字符串,并且服务器在发送这个 Cookie 之前,会对这个含有 Session Id 的 Cookie 进行“签名”。也就是说,如果黑客修改了这个 Session Id ,那么服务器就无法识别这个 Session Id,因此就可以保证信息传输的安全性。

🌴三、Cookie 和 Session 的区别

🍕1. Cookie 可以存储在浏览器或本地,Session 只能存储在服务器。

🍔2. Session 能够存储任意的 Java 对象,Cookie 只能存储 String 类型的对象。

🍟3. Session 比 Cookie 更具有安全性(Cookie 有安全隐患,通过拦截或本地文件可以找到用户的 Cookie ,然后进行攻击)

🌭4. Session 占用服务器性能,如果 Session 过多,会增加服务器压力。

🍿5. 单个 Cookie 有大小限制;而 Session  是没有大小限制的 ,它的它所存储的数据量和服务器大小有关。

🥓6. Cookie 可以单独使用,也可以搭配 Session 使用。

🌵四、实现一个简单的登录功能

🥗核心方法:

HttpServletRequest 类中的相关方法:

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

实际开发中,使用 getCookies() 的场景非常少,主要还是getSession()方法。

我们主要来看看 getSession 方法:

这个方法在使用时需要传入一个boolean值:

        当我们传入的时true时,首先会读取请求中Cookie里面的 Session Id ,在服务器这边根据 Session Id 来查询对应的 Session 对象。

        如果查询到了,就直接返回这个 Session 对象。

        如果没有查询到,就会才创建一个 Session 对象,同时生成一个 Session Id , 以 Session Id 为key,以 Session 对象为value,把这个键值对存储在服务器里面的一个hash表中 同时把 Session Id 以 set-Cookie 的方法返回给浏览器。

        当我们传入的是false时,读取请求中 Cookie 里面的 Session Id ,在服务器这边根据 Session Id 来查询对应的 Session 对象 。

        如果查询到了,就直接返回这个 Session 对象。

        如果没有查询到,就返回一个null。

现在我们通过实现用户登录的例子来综合的理解Cookie和Session:

提交的数据格式为form表单的形式  Content-Type:application/x-www-form-urlencoded

例如username=zhangsan&password=123

一般向这样的登录请求,都是使用post方法比较好。属于是使用习惯。

首先要实现一个用户登录的场景,我们先要得到前端的页面。

🥙前端页面:

<!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>登录页面</title>
    </head>
    <body>
        <form action="login" method="post">
            <input type="text" name="username">
            <input type="password" name="password">
            <input type="submit" value="login">
        </form>
    </body>
</html>

可以看到上述代码中,我们是以form表单的形式提交的数据,方法是post,路径为login。

页面效果:

        当我们点击登录的时候,就会把我们输入框里面的用户名和密码以form表单的形式通过post方法向路径为login提交数据。

        如果用户名和密码正确,我们就跳转到一个新的页面,如果不正确,我们就提交用户名或密码错误。

🥪后端代码:

后端我们分了两个 Servlet 来实现,一个 Servlet 用来实现账号密码验证功能,一个用来生成主页。

🍧账号密码校验的Servlet:

package login;

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 {
        // 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");
    }
}

🍨生成主页的 Servlet:

package login;

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;

// 这个 Servlet 用来动态的生成主页面.
@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");
        // 这个 ession.getAttribute()方法得到的对象是Object类的,因此,要把它强转为 String 类
        if (username == null) {
            // 虽然有会话对象, 但是里面没有必要的属性, 也认为是登录状态异常.
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("当前用户未登录!");
            return;
        }

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

我们打开页面,

 输入账号密码:

 点击登录,查看抓包结果:

这个是 login 的请求报文:

此处的请求为post请求,路径为login,提交数据格式和我们前面约定的格式一致。

这个包中并没有Cookie字段。因为此时服务器还不知道是否用户名和密码正确,当用户名和密码正确之后,服务器才会创建Session对象,同时在响应中sessionId发送给浏览器。

这个是 login 的响应报文:

可以看出在相应包里面有一个 Set-cookie 字段。

此时页面成功的跳转到了index页面,也就是说明此时成功登录。 
 

这个是 index 的请求报文:

 在抓包结果里面我们就发现了Cookie字段而这个Cookie字段里面的值和第一个登录时服务器给浏览器返回的set-Cookie里面的SessionId的值一致。服务器就是通过这个sessionId来区分不同的用户的。服务器也就知道是那个用户在访问页面了。 

这个是 index 的响应报文:

这就是本篇的全部内容啦~~

 

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值