HTTP协议中的Cookie和Session

目录

Cookie的概念

Cookie的来源、存储信息、最终的去处  

Session

Session的概念

Session的本质

Cookie和Session之间的工作

Cookie和Session的区别 

Cookie和Session的方法 


Cookie的概念

Cookie是HTTP协议中的一个字段,同时也是浏览器在客户端这边保存数据的一种方式

登录一个网页,用抓包工具抓一下登录请求就可以看到:

 

Cookie的来源、存储信息、最终的去处  

  • Cookie是服务器产生的,服务器可以通过响应中的Set-Cookie字段来设置,返回给浏览器
  • Cookie是存储在浏览器这边的,浏览器会根据域名/地址来分别存储Cookie。Cookie里面存储的是键值对结构的字符串,这个字符串都是程序员自己定义的
  • Cookie的作用就是用来存储用户的信息,然后当用户再次向服务器发出请求数据的时候,请求中就会带上Cookie,它就像一把钥匙,然后拿着它去开对应的门。 

 

 令牌就是Cookie中的字段

Session

Session的概念

Session叫做会话,他主要是用来检查请求数据中的Cookie字段是否在服务器存在和是否合法

因为Cookie是由服务器产生的,所以服务器中会存储Cookie中的一些信息,当浏览器再次请求数据时,服务器就会将Cookie中的一些字段和服务器存储的信息比对,如果比对成功就让这次请求通过,如果比对失败则不会通过这次请求。而Session所做的就是这样的工作,它就像检票员,如果发现你不是这趟车的就不会让你上车。

Session的本质

Session是在服务器这边存储的,可以简单的把Session想象成一个hash表,其中的key就是令牌的ID(token/sessionId),value就是程序员自己定义的数据(这里可以存储用户的身份信息等)。

sessionId是服务器生成的一个“唯一字符串”,每一个登录的用户都有自己唯一不同的ID,这就好比身份证一样,每个人都不相同。

Cookie和Session之间的工作

 

总结上面的工作就是:

  1. 当用户登录的时候,服务器在session中新增一个记录,并把sessionId/token返回给客户端
  2. 客户端后续再给服务器发送请求的时候,需要在请求中带上sessionId/token
  3. 服务器收到请求之后,根据请求中的sessionId/token在session信息中获取到对应的用户信息,再进行后续操作 

Cookie和Session的区别 

  • Cookie是客户端机制,Session是服务器机制
  • Cookie和Session经常在一起配合使用,但是不一定的必须配合使用。完全可以Cookie来保存一些数据在客户端,然后Session中的sessionId也不一定的通过Cookie/Set-Cookie来传递 

Cookie和Session的方法 

HttpSession getSession()            
功能有两个:
尝试根据当前请求中的sessionId来获取当前的session
1.如果session不存在,就创建(创建一个HttpSession对象,作为value。创建一个sessionId作为Key。把key和value插入到hash表中,同时把这个sessionId通过Set-Cookie字段返回给浏览器)
2.如果存在就返回
void addCookie(Cookie cookie)            功能:把指定的cookie添加到响应中
Object getAttribute(String name)         功能:返回session会话中具有指定名称的对象,如果没有指定名称的对象,则返回null

通过一个登录案例来探究这些方法和会话机制:

首先写一个html,里面包含用户名密码的输入框,以及登录按钮。然后要有一个LogServlet来处理登录请求。在搞一个IndexServlet,模拟登录完成以后,跳转到的主页面,在这个页面就可以获取到用户的身份信息

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
    <form action="login" method="POST">
        用户名: <input type="text" name="username">
        <br>
        密码: <input type="password" name="password">
        <br>
        <input type="submit" value="登录">
    </form>
</body>
</html>
@WebServlet("/login")
public class LoginSelvlet 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(!"zhangsan".equals(username)||!"123".equals(password)){
            //登录失败
            resp.getWriter().write("登陆失败");
            return;
        }
        //3.登陆成功,则创建出一个会话来,会话不存在就创建
        //会话是根据请求中的sessionId来查的,sessionId是在Cookie中的
        //但是此处是首次登录,此时请求中是没有Cookie(Cookie是在服务器返回)
        //此时就会触发"找不到就创建"这样的流程,同时这里进行的操作:先创建出一个HttpSession对象(作为value),再成一个随机的字符串,作为sessionId(作为key)
        //把这个key和value插入到hash表中,同时把这个生成的sessionId通过Set-Cookie字段返回给浏览器
        HttpSession httpSession = req.getSession(true);
        //还可以存入程序猿自定义的数据,可以存入身份信息(用户名和登录次数)
        httpSession.setAttribute("username","zhangsan");
        httpSession.setAttribute("loginCount",0);
        //4.让页面跳转到主页,使用重定向的方式实现即可
        resp.sendRedirect("index");
    }
}
@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.判定当前用户是否已经登录了,(请求中有没有sessionId,以及sessionId是否合法)
        //如果会话不存在,就不能创建了,只是查询,不是登录
        HttpSession httpSession = req.getSession(false);
        if(httpSession==null){
            //当前没有找到合法会话,当前用户尚未登录
            //返回并让用户重新登录
            System.out.println("登录失败");
            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());

    }
}

启动服务器,在浏览器中输入相关URL后:

 

再通过抓包工具可以看出:

第一次请求中的数据里面是没有Cookie的

 

但是响应中就返回了一个Cookie,这个Cookie就是服务器生成的

 

上面的响应中还有一个Location的字段,他表示要跳转到那个URL,根据URL就会跳转到index路劲下面,于是就触发第二次请求:

 

可以看到第二次请求中就带有Cookie,而这个Cookie就是第一次响应中的Cookie,而里面的JSESSIONID就是sessionId,它=号后面的一串字符串就是十六进制的随机字符串。在这个请求头中,还有一个Referer字段,它表示从哪个URL跳过来的。

再来看第二次请求中的响应内容:

 

第二次响应中的body就是要输出在浏览器界面上的内容。

后续的请求中都带有相同的Cookie:

 

总结上面的代码:

 

 

为了展示效果明显,这里就不跳转到index路径下面的Servlet了,而是让他跳转到一个指定的html页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>待办事项</title>
    <!--实现页面样式-->
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        .container {
/*            background-color: transparent;*/
            width: 800px;
            height: 800px;
            margin: 0 auto;
            display: flex;
        }

        .todo,
        .done {
            width: 50%;
            height: 100%;
        }

        .container h3 {
            height: 50px;
            text-align: center;
            line-height: 50px;
            background-color: #FB7299;
            color: #fff;
        }

        .nav {
            width: 800px;
            height: 100px;
            margin: 0 auto;
            display: flex;
            align-items: center;
        }

        .nav input {
            padding-left: 5px;
            width: 600px;
            height: 50px;
        }

        .nav button {
            width: 200px;
            height: 50px;
        }

        .nav button {
            width: 200px;
            height: 50px;
            /*去除按钮周围的边框,button会自带2个像素的实线边框,因此要去掉*/
            border: none;
            background-color: #6CD083;
            color: #ffffff;
        }

        .row {
            height: 50px;
            display: flex;
            align-items: center;
        }

        .row input {
            /*设置上下外边距为0,左右外边距为10*/
            margin: 0 10px;
        }

        .row span {
            width: 300px;
        }

        .row button {
            width: 50px;
            height: 40px;
        }
    </style>
</head>
<body>
    <!--创建页面布局-->
    <div class="nav">
        <input type="text">
        <button>新建任务</button>
    </div>
    <div class="container">
        <div class="todo">
            <h3>未完成</h3>
            <!--这里只是方便写代码才设置这样的操作,但实际开发中还是以操作为主-->
<!--            <div class="row">
                <input type="checkbox">
                <span>吃饭</span>
                <button>删除</button>
            </div>-->
        </div>
        <div class="done">
            <h3>已完成</h3>
        </div>
    </div>

    <!--实现页面行为-->
    <script>
        //实现新增任务
        var addTaskButton = document.querySelector('.nav button');
        addTaskButton.onclick = function () {
            //1.获取到输入框
            var input = document.querySelector('.nav input');
            //2.获取到输入框内容
            var taskContent = input.value;
            if(taskContent==''){
                console.log('当前任务为空不能新增任务');
                return;
            }
            //3.根据内容新建一个元素节点
            var row = document.createElement('div');
            row.className = 'row';
            var checkbox = document.createElement('input');
            checkbox.type = 'checkbox';
            var span = document.createElement('span');
            span.innerHTML = taskContent;
            var button = document.createElement('button');
            button.innerHTML = '删除';

            row.appendChild(checkbox);
            row.appendChild(span);
            row.appendChild(button);

            //4.把新节点插入到TODO中
            var todo = document.querySelector('.todo');
            todo.appendChild(row);

            //5.把输入框里面的内容删除
            input.value = '';

            //点击复选框后将元素放到"已完成"
            //6.给checkbox注册点击事件
            checkbox.onclick = function () {
                /*操作row这个对象,看是吧row这个对象放在TODO里面还是done里面
                注意,是先触发checked为true,然后再调用onclick函数*/
                if (this.checked) {
                    var target = document.querySelector('.done');
                } else {
                    var target = document.querySelector('.todo');
                }
                target.appendChild(row);
            }

            //点击删除按钮删除该任务
            //7.给删除按钮注册点击事件
            button.onclick = function (){
                /*这里row就是那个要删除的元素(child=>row)
                row的parent可能是todo,也可能是done,这里可以直接通过parentNode属性来获取row的父元素*/
                var parent = row.parentNode;
                parent.removeChild(row);
            }
        }
    </script>
</body>
</html>
@WebServlet("/login")
public class LoginSelvlet 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(!"zhangsan".equals(username)||!"123".equals(password)){
            //登录失败
            resp.getWriter().write("登陆失败");
            return;
        }
        //3.登陆成功,则创建出一个会话来,会话不存在就创建
        //会话是根据请求中的sessionId来查的,sessionId是在Cookie中的
        //但是此处是首次登录,此时请求中是没有Cookie(Cookie是在服务器返回)
        //此时就会触发"找不到就创建"这样的流程,同时这里进行的操作:先创建出一个HttpSession对象(作为value),再成一个随机的字符串,作为sessionId(作为key)
        //把这个key和value插入到hash表中,同时把这个生成的sessionId通过Set-Cookie字段返回给浏览器
        HttpSession httpSession = req.getSession(true);
        //还可以存入程序猿自定义的数据,可以存入身份信息(用户名和登录次数)
        httpSession.setAttribute("username","zhangsan");
        httpSession.setAttribute("loginCount",0);
        //4.让页面跳转到主页,使用重定向的方式实现即可
        resp.sendRedirect("http://127.0.0.1:8080/messageWall/work.html");
    }
}

启动服务器,输入URL,然后登录:

 

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咸鱼吐泡泡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值