• HTTP协议中的Cookie和Session


    目录

    Cookie

    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的方法 

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

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

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

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>登录页面title>
    6. head>
    7. <body>
    8. <form action="login" method="POST">
    9. 用户名: <input type="text" name="username">
    10. <br>
    11. 密码: <input type="password" name="password">
    12. <br>
    13. <input type="submit" value="登录">
    14. form>
    15. body>
    16. html>
    1. @WebServlet("/login")
    2. public class LoginSelvlet extends HttpServlet {
    3. @Override
    4. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    5. resp.setContentType("text/html;charset=utf-8");
    6. //1.先从请求body中读取用户名和密码
    7. String username = req.getParameter("username");
    8. String password = req.getParameter("password");
    9. //2.判定一下用户名和密码是否正确(读固定的密码)
    10. if(!"zhangsan".equals(username)||!"123".equals(password)){
    11. //登录失败
    12. resp.getWriter().write("登陆失败");
    13. return;
    14. }
    15. //3.登陆成功,则创建出一个会话来,会话不存在就创建
    16. //会话是根据请求中的sessionId来查的,sessionId是在Cookie中的
    17. //但是此处是首次登录,此时请求中是没有Cookie(Cookie是在服务器返回)
    18. //此时就会触发"找不到就创建"这样的流程,同时这里进行的操作:先创建出一个HttpSession对象(作为value),再成一个随机的字符串,作为sessionId(作为key)
    19. //把这个key和value插入到hash表中,同时把这个生成的sessionId通过Set-Cookie字段返回给浏览器
    20. HttpSession httpSession = req.getSession(true);
    21. //还可以存入程序猿自定义的数据,可以存入身份信息(用户名和登录次数)
    22. httpSession.setAttribute("username","zhangsan");
    23. httpSession.setAttribute("loginCount",0);
    24. //4.让页面跳转到主页,使用重定向的方式实现即可
    25. resp.sendRedirect("index");
    26. }
    27. }
    1. @WebServlet("/index")
    2. public class indexServlet extends HttpServlet {
    3. @Override
    4. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    5. //根据当前用户请求中的sessionId,获取到用户信息,并且显示到页面上
    6. resp.setContentType("text/html;charset=utf-8");
    7. //1.判定当前用户是否已经登录了,(请求中有没有sessionId,以及sessionId是否合法)
    8. //如果会话不存在,就不能创建了,只是查询,不是登录
    9. HttpSession httpSession = req.getSession(false);
    10. if(httpSession==null){
    11. //当前没有找到合法会话,当前用户尚未登录
    12. //返回并让用户重新登录
    13. System.out.println("登录失败");
    14. return;
    15. }
    16. //2.用户登录成功就可以从HttpSession获取到用户里面的信息
    17. String username = (String)httpSession.getAttribute("username");
    18. Integer loginCount = (Integer)httpSession.getAttribute("loginCount");
    19. loginCount = loginCount+1;
    20. httpSession.setAttribute("loginCount",loginCount);
    21. //3.返回一个HTML页面
    22. StringBuilder html = new StringBuilder();
    23. html.append("
      用户: "+username+"
      "
      );
    24. html.append("
      访问次数: "+loginCount+"
      "
      );
    25. resp.getWriter().write(html.toString());
    26. }
    27. }

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

     

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

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

     

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

     

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

     

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

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

     

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

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

     

    总结上面的代码:

     

     

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

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>待办事项title>
    6. <style>
    7. * {
    8. margin: 0;
    9. padding: 0;
    10. box-sizing: border-box;
    11. }
    12. .container {
    13. /* background-color: transparent;*/
    14. width: 800px;
    15. height: 800px;
    16. margin: 0 auto;
    17. display: flex;
    18. }
    19. .todo,
    20. .done {
    21. width: 50%;
    22. height: 100%;
    23. }
    24. .container h3 {
    25. height: 50px;
    26. text-align: center;
    27. line-height: 50px;
    28. background-color: #FB7299;
    29. color: #fff;
    30. }
    31. .nav {
    32. width: 800px;
    33. height: 100px;
    34. margin: 0 auto;
    35. display: flex;
    36. align-items: center;
    37. }
    38. .nav input {
    39. padding-left: 5px;
    40. width: 600px;
    41. height: 50px;
    42. }
    43. .nav button {
    44. width: 200px;
    45. height: 50px;
    46. }
    47. .nav button {
    48. width: 200px;
    49. height: 50px;
    50. /*去除按钮周围的边框,button会自带2个像素的实线边框,因此要去掉*/
    51. border: none;
    52. background-color: #6CD083;
    53. color: #ffffff;
    54. }
    55. .row {
    56. height: 50px;
    57. display: flex;
    58. align-items: center;
    59. }
    60. .row input {
    61. /*设置上下外边距为0,左右外边距为10*/
    62. margin: 0 10px;
    63. }
    64. .row span {
    65. width: 300px;
    66. }
    67. .row button {
    68. width: 50px;
    69. height: 40px;
    70. }
    71. style>
    72. head>
    73. <body>
    74. <div class="nav">
    75. <input type="text">
    76. <button>新建任务button>
    77. div>
    78. <div class="container">
    79. <div class="todo">
    80. <h3>未完成h3>
    81. div>
    82. <div class="done">
    83. <h3>已完成h3>
    84. div>
    85. div>
    86. <script>
    87. //实现新增任务
    88. var addTaskButton = document.querySelector('.nav button');
    89. addTaskButton.onclick = function () {
    90. //1.获取到输入框
    91. var input = document.querySelector('.nav input');
    92. //2.获取到输入框内容
    93. var taskContent = input.value;
    94. if(taskContent==''){
    95. console.log('当前任务为空不能新增任务');
    96. return;
    97. }
    98. //3.根据内容新建一个元素节点
    99. var row = document.createElement('div');
    100. row.className = 'row';
    101. var checkbox = document.createElement('input');
    102. checkbox.type = 'checkbox';
    103. var span = document.createElement('span');
    104. span.innerHTML = taskContent;
    105. var button = document.createElement('button');
    106. button.innerHTML = '删除';
    107. row.appendChild(checkbox);
    108. row.appendChild(span);
    109. row.appendChild(button);
    110. //4.把新节点插入到TODO中
    111. var todo = document.querySelector('.todo');
    112. todo.appendChild(row);
    113. //5.把输入框里面的内容删除
    114. input.value = '';
    115. //点击复选框后将元素放到"已完成"
    116. //6.给checkbox注册点击事件
    117. checkbox.onclick = function () {
    118. /*操作row这个对象,看是吧row这个对象放在TODO里面还是done里面
    119. 注意,是先触发checked为true,然后再调用onclick函数*/
    120. if (this.checked) {
    121. var target = document.querySelector('.done');
    122. } else {
    123. var target = document.querySelector('.todo');
    124. }
    125. target.appendChild(row);
    126. }
    127. //点击删除按钮删除该任务
    128. //7.给删除按钮注册点击事件
    129. button.onclick = function (){
    130. /*这里row就是那个要删除的元素(child=>row)
    131. row的parent可能是todo,也可能是done,这里可以直接通过parentNode属性来获取row的父元素*/
    132. var parent = row.parentNode;
    133. parent.removeChild(row);
    134. }
    135. }
    136. script>
    137. body>
    138. html>
    1. @WebServlet("/login")
    2. public class LoginSelvlet extends HttpServlet {
    3. @Override
    4. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    5. resp.setContentType("text/html;charset=utf-8");
    6. //1.先从请求body中读取用户名和密码
    7. String username = req.getParameter("username");
    8. String password = req.getParameter("password");
    9. //2.判定一下用户名和密码是否正确(读固定的密码)
    10. if(!"zhangsan".equals(username)||!"123".equals(password)){
    11. //登录失败
    12. resp.getWriter().write("登陆失败");
    13. return;
    14. }
    15. //3.登陆成功,则创建出一个会话来,会话不存在就创建
    16. //会话是根据请求中的sessionId来查的,sessionId是在Cookie中的
    17. //但是此处是首次登录,此时请求中是没有Cookie(Cookie是在服务器返回)
    18. //此时就会触发"找不到就创建"这样的流程,同时这里进行的操作:先创建出一个HttpSession对象(作为value),再成一个随机的字符串,作为sessionId(作为key)
    19. //把这个key和value插入到hash表中,同时把这个生成的sessionId通过Set-Cookie字段返回给浏览器
    20. HttpSession httpSession = req.getSession(true);
    21. //还可以存入程序猿自定义的数据,可以存入身份信息(用户名和登录次数)
    22. httpSession.setAttribute("username","zhangsan");
    23. httpSession.setAttribute("loginCount",0);
    24. //4.让页面跳转到主页,使用重定向的方式实现即可
    25. resp.sendRedirect("http://127.0.0.1:8080/messageWall/work.html");
    26. }
    27. }

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

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    2022年8月9日:使用 ASP.NET Core 为初学者构建 Web 应用程序--使用 HTML、CSS 和 Javascript 构建简单的网站
    【物联网】NB-IoT
    JavaScript从入门到精通系列第二十五篇:JavaScript中的Date对象
    Maya——1——在maya中,用Arnold(阿诺德)还原Subtance Painter(sp)中的材质效果。
    vue-element-admin 综合开发四:axios安装和封装、mock安装/学习/使用
    Servlet
    The core spirit of sentences
    九、MyBatis的缓存
    js监听页面滚动
    Kepler.gl笔记:地图交互
  • 原文地址:https://blog.csdn.net/yahid/article/details/126403735