• Session会话追踪的实现机制


    一. 概述
    在Web应用程序中,我们经常需要跟踪用户的身份。当用户访问一个页面或者对自己的购物车进行操作时,Web程序是如何识别用户身份的?
    HTTP协议是无状态协议,即Web应用程序无法区分收到的HTTP请求是否是同一个浏览器发出的。为了跟踪用户状态,服务器向浏览器分配了一个唯一ID,并以Cookie的形式发送到服务器,服务器在后续访问时总是附带此Cookie

    session

    1. Session是什么?
      把基于唯一ID识别用户身份的机制成为Session
      这个唯一ID是什么?
    - 用户第一次访问服务器后,会自动创建Session并获得一个Session ID
    - 根据Session ID,创建一个名称为”JSESSIONID“的Cookie, 将Session_ID保存在Cookie
    - 接下来的每次发起请求时,客户端浏览器都会在请求中,添加JESSIONID,用于服务器确认身份。
    
    • 1
    • 2
    • 3

    2.如何获取Session?

    HttpSession session = request.getSession();
    
    • 1

    服务器识别Session的关键就是依靠一个名为JSESSIONID的Cookie。

    • 在Servlet第一次调用request.getSession()时,Servlet容器会自动创建一个Session ID,然后通过名为JSESSIONID的Cookie发送给浏览器
    • 放入Session 的数据不能太大,否则会影响服务器的运行效率:
      使用Session时,由于服务器把所有用户的Session都存储在内存中,如果遇到内存不足的情况,就把部分不活动地Session序列化到磁盘,这样会大大降低
      服务器的运行效率。

    【发送请求】

    package com.ape.web.servlet;
    
    import java.io.IOException;
    
    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;
    
    @WebServlet("/test_session.do")
    public class TestSessionServlet extends HttpServlet{
    
    	@Override
    	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    		System.out.println("GET请求:TestSessionServlet被请求到了!");
    		
    		HttpSession session = req.getSession();
    		System.out.println(session.getId());
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    【运行结果】
    在这里插入图片描述

    • 如果用户一段时间内没有访问服务器,那么Session会自动失效。
    • 下次访问即使带着上次分配的Session ID访问,服务器也会认为这是一个新用户,会分配新的Session ID。
    • 一次Session会话中往往包含着若干次request请求。

    在这里插入图片描述

    当我们对服务器发送3次请求时,其Session ID一致:
    在这里插入图片描述

    Cookies

    Servlet提供的HttpSession本质上就是一个通过名为JSESSIONID的Cookie来跟踪用户会话的,除了这个名称外,其他名称的Cookie可以任意使用。

    1. 查看Cookies:
      会看到一段时间内没有访问服务器,上一个Session自动失效。继续访问时,服务器会分配新的Session ID。
      Session可以唯一标识用户身份在这里插入图片描述
      2.设置setPath(“/”),浏览器会根据此前缀来决定是否发送Cookie

    如果一个Cookie调用了setPath(“/user/”),那么浏览器只有在请求以"/user/"开头的路径时才会附加此Cookie。

    1. 我们还可以设置过期时间setMaxAge(),如果未设置,则默认过期时间为Session(服务器关闭或重启时此Session过期)。
      在这里插入图片描述【添加Cookies并设置过期时间】
    package com.ape.web.servlet;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @WebServlet("/test_cookie.do")
    public class TestCookieServlet extends HttpServlet{
    
    	@Override
    	protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
    		System.out.println("测试添加cookie!");
    		
    		// 创建Cookie对象
    		Cookie cookie1 = new Cookie("phone_number", "18710404709");
    		cookie1.setMaxAge(60*60*24);
    		
    		Cookie cookie2 = new Cookie("user_name", "旺旺仙贝");
    		cookie2.setMaxAge(60*60*24);
    		
    		Cookie cookie3 = new Cookie("user_email", "31391@126.com");
    		cookie3.setMaxAge(60*60*24); // 24h		
    		// 响应
    		response.addCookie(cookie1); // 将Cookie添加至响应头
    		response.addCookie(cookie2); 
    		response.addCookie(cookie3); 		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    我们可以在服务器中F12看查Cookies是否添加成功
    在这里插入图片描述
    【测试获取Cookie】

    package com.ape.web.servlet;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @WebServlet("/test_get_cookie_value.do")
    public class TestGetCookieValueServlet extends HttpServlet {
    
    	@Override
    	protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
    		System.out.println("测试获取Cookie");
    		
    		// 获取该客户端本次请求头(Request Header)中所有的Cookie
    		Cookie[] cookieArray = request.getCookies();
    		
    		for(Cookie ck : cookieArray) {
    			System.out.println(ck.getName());
    			System.out.println(ck.getValue());
    			System.out.println();
    		}		
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    【运行结果】
    在这里插入图片描述
    4. 既然我们可以追踪到用户身份,那我们如何查看此用户的访问量呢?

    package com.ape.web.servlet;
    
    import java.io.IOException;
    
    import javax.servlet.Servlet;
    import javax.servlet.ServletContext;
    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;
    
    @WebServlet("/application.do")
    public class TestApplicationServlet extends HttpServlet{
    	
    	@Override
    	protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
    		// 会话范围
    		HttpSession session = request.getSession();
    		if(session.getAttribute("session_counter") != null) {
    			
    		}
    		
    		// 应用范围:不区分用户,访问量++
    		ServletContext application = request.getServletContext();
    		System.out.println("Context Path:" + application.getContextPath());
    		System.out.println("Real Path:" + application.getRealPath("/"));
    		
    		if(application.getAttribute("app_counter") == null) {
    			application.setAttribute("app_counter", 1);
    			System.out.println("总访问量:1" );
    		}else {
    			int counter = Integer.parseInt(application.getAttribute("app_counter").toString());
    			application.setAttribute("app_counter", counter+1);
    			System.out.printf("总访问量:%d\n" ,counter+1);
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    【运行结果】
    在这里插入图片描述

  • 相关阅读:
    [附源码]java毕业设计 停车场管理系统
    序列和【牛客网】
    MybatisPlus listObjs 返回只查询一个字段类型集合
    OpenJudge NOI 2.1 3526:最简真分数
    算法学习 |从无到有 刷爆LeetCode算法神器
    聊聊Redis sentinel 机制
    高斯消元法
    Linux系统笔记Ⅰ
    05-内存分配与回收策略
    linux文件存储之inode,硬链接,软链接详解
  • 原文地址:https://blog.csdn.net/weixin_45939128/article/details/126518216