• 一文学懂Cookie与Session的区别


    在这里插入图片描述

    正文开始

    一张思维导图了解

    在这里插入图片描述

    Session用来实现用户会话
    Session对应类名:HttpSession(javax.servlet.http.HttpSession)
    Session是JSP内置的对象

    会话的理解

    • 什么是会话?
      • 用户打开浏览器,对浏览器进行一系列操作,最终关闭浏览器的过程中,这个整个过程叫做 : 会话。会话在服务器端也对应一个Java对象,这个Java对象叫做 : session
      • 什么是一次请求:用户在浏览器上点击了一下,然后到页面停下来,可以粗略认为是一次请求。请求对应的服务器端的Java对象是:request。
      • 一个会话当中包含多次请求。( 一次会话对应N次请求。
    • 在Java的servlet规范当中,session对应的类名:HttpSession。
    • Session机制实际上是一个规范。然后不同的语言对这种会话机制都有实现。

    对于会话有了基本的理解以后,我们来看一下,它的作用是什么

    Seesion的作用

    • Session对象最主要的作用是:保存会话状态。(用户登录成功了,这是一种登录成功的状态,你怎么把登录成功的状态一直保存下来呢?使用session对象可以保留会话状态。

      image-20220828193623047

    既然Session是用来保存会话状态的,那么我们就会有一个疑惑,为什么要用它来保存会话状态。因为客户端发送请求以后,它和服务器的连接就断开了。

    image-20220828193742715
    • 为什么需要Session对象来保存会话状态呢 ?

      • 因为HTTP是无状态的
      • 什么是无状态:请求的时候,B和S是连接的,但是请求结束之后,连接就断了。为什么要这么做?HTTP协议为什么要设计成这样?因为这样的无状态协议,可以降低服务器的压力。请求的瞬间是连接的,请求结束之后,连接断开,这样服务器压力小。
      • 只要B/S断开了,也就是关闭浏览器这个动作,服务器是不知道的。
    • 张三打开一个浏览器A,李四打开一个浏览器B,访问服务器之后,在服务器端会生成:

      • 张三专属的 Session 对象
      • 李四专属的 Session 对象
    • 为什么不使用request对象保存会话状态?为什么不使用ServletContext对象保存会话状态?

      • request.setAttribute()存,request.getAttribute()取,ServletContext也有这个方法。request是请求域。ServletContext是应用域。
      • request 是一次请求一个对象。
      • ServletContext 对象是服务器启动的时候创建,服务器关闭的时候销毁,这个ServletContext对象只有一个。
      • ServletContext对象的域太大。
      • request请求域(HttpServletRequest)、session会话域(HttpSession)、application域(ServletContext)
      • request < session < application

    HTTP协议的无状态特点

    服务器没有办法识别每一次请求是从哪一台电脑访问的,它能接收请求,但是它不知道这个请求是从哪里来的,不知道要响应给谁。比如说我们买东西,添加购物车,由于它无法识别是来自哪一个客户端的请求,它就可能把我们的请求发送给其他人,所以必须要有一种技术来让服务器知道请求来自哪里,这就是会话技术

    **下面这一张图很清晰的概述了我们为什么需要会话技术 **

    image-20220828193924749

    Seesion的实现原理(重点)

    • Session的实现原理 :
      • JSESSIONID = xxx 这个是以Cookie的形式保存在浏览器的内存中的。浏览器只要关闭。这个cookie就没有了。
      • Session列表是一个Map,Map的 key可以 SeesionId ,Map的 value 是 Session 对象。
      • 用户发送第一次请求时,服务器生成Session对象,同时生成SeesionId,然后将这个id以cookie的形式发送给浏览器。
      • 用户发送第二次 ,自动将浏览器内存中的SeesionId发送给服务器,服务器根据SeesionId来查找Seesion对象。
      • 关闭浏览器,内存消失,cookie消失,sessionid消失,会话等同于结束。

    image-20220828191330094

    • 总结一下到目前位置我们所了解的域对象:

      • request(对应的类名:HttpServletRequest)

        • 请求域(请求级别的)
      • session(对应的类名:HttpSession)

        • 会话域(用户级别的)
      • application(对应的类名:ServletContext)

        • 应用域(项目级别的,所有用户共享的。)
      • 这三个域对象的大小关系

      • request < session < application

      • 他们三个域对象都有以下三个公共的方法:

        • setAttribute(向域当中绑定数据)
        • getAttribute(从域当中获取数据)
        • removeAttribute(删除域当中的数据)
    • 使用原则:尽量使用小的域。

    Session的常用方法

    Session在实际开发中是用来记录我们的用户信息的,我们不需要每一次访问都输入用户名和密码,如果登录过一次,后面可以不用再输入,但是这是有一个周期的,不可能一直存着的,默认失效时间为1800秒(也就是30分钟)

    Session数据的存取

    • Session域对象数据的存取和其他三个域对象PageContext、Request、ServletContext是一样的。只需要调用下面两个方法:

      • setAttribute 设置属性
      • getAttribute 获取属性
    • 编写下面的java代码去访问,就可以在Session域中设置属性,和获取属性。

    protected void setAttribute(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		// 第一个调用就是获取一个新的Session。如果Session已经创建过。就获取原来的会话。
    		HttpSession session = request.getSession();
    		// 设置数据
    		session.setAttribute("abc", "abc value");
    		response.getWriter().write("设置属性值成功!");
    	}
    	
    	protected void getAttribute(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		// 第一个调用就是获取一个新的Session。如果Session已经创建过。就获取原来的会话。
    		HttpSession session = request.getSession();
    		// 设置数据
    		String value = (String) session.getAttribute("abc");
    		response.getWriter().write("获取abc的属性值:" + value);
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    修改session.html 中访问的连接地址,然后点击访问。

    <li>
    	<a href="sessionServlet?action=setAttribute" >Session域数据的存储a>li>
    
    <li>
    	<a href="sessionServlet?action=getAttribute" >Session域数据的获取a>li>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    访问后效果图:

    1558628097144

    1558628140230

    Session 的有效时间

    • 基本原则

      • Session对象在服务器端不能长期保存,它是有时间限制的,超过一定时间没有被访问过的Session对象就应该释放掉,以节约内存。所以Session的有效时间并不是从创建对象开始计时,到指定时间后释放。而是从最后一次被访问开始计时,统计其“空闲”的时间。
    • 默认时效

      • 在tomcat的conf 目录下web.xml配置文件中能够找到如下配置:

        
          
          
        
            <session-config>
                <session-timeout>30session-timeout>
            session-config>
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8

        说明:Session对象默认的最长有效时间为30分钟。

    • 手动设置1:全局

      • 我们也可以在自己工程的web.xml文件中配置Session会话的超时时间为10分钟。

      • 记住一点,我们在web.xml文件中配置的Session会话超时时间是对所有Session都生效的。

        
        <session-config>
        	
            <session-timeout>10session-timeout>
        session-config>
        
        • 1
        • 2
        • 3
        • 4
        • 5
    • 手动设置2:局部

      • int getMaxInactiveInterval() 获取超时时间。以秒为单位。
      • setMaxInactiveInterval (int seconds) 设置用户多长时间没有操作之后就会Session过期。以秒为单位。
        • 如果是正数。表示用户在给定的时间内没有任意操作,Session会话就会过期。
        • 如果是非正数(零&负数)。表示Session永不过期。
    • 强制失效

      • invalidate()
    • 示例代码

    Session3秒之后超时
    // 第一个调用就是获取一个新的Session。如果Session已经创建过。就获取原来的会话。
    HttpSession session = request.getSession();
    // 设置过期时间为3秒 
    session.setMaxInactiveInterval(3);
    
    Session1分钟之后超时
    // 第一个调用就是获取一个新的Session。如果Session已经创建过。就获取原来的会话。 
    HttpSession session = request.getSession();
    // 设置过期时间为1分钟
    session.setMaxInactiveInterval(60);
    
    Session1小时之后超时
    // 第一个调用就是获取一个新的Session。如果Session已经创建过。就获取原来的会话。
    HttpSession session = request.getSession();
    // 设置过期时间为1小时
    session.setMaxInactiveInterval(60 * 60);
    
    Session1天之后超时
    // 第一个调用就是获取一个新的Session。如果Session已经创建过。就获取原来的会话。
    HttpSession session = request.getSession();
    // 设置过期时间为1天
    session.setMaxInactiveInterval(60 * 60 * 24);
    
    Session1周之后超时
    // 第一个调用就是获取一个新的Session。如果Session已经创建过。就获取原来的会话。
    HttpSession session = request.getSession();
    // 设置过期时间为1周
    session.setMaxInactiveInterval(60 * 60 * 24 * 7);
    
    Session永远不超时
    // 第一个调用就是获取一个新的Session。如果Session已经创建过。就获取原来的会话。
    HttpSession session = request.getSession();
    // 设置永远不超时
    session.setMaxInactiveInterval(-1);
    
    Session马上超时(失效)
    // 第一个调用就是获取一个新的Session。如果Session已经创建过。就获取原来的会话。
    HttpSession session = request.getSession();
    // 让Session对象立即过期
    session.invalidate();
    
    • 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
    • 40
    • 41

    Session对象的释放

    • Session对象空闲时间达到了目标设置的最大值,自动释放

    • Session对象被强制失效

    • Web应用卸载

    • 服务器进程停止

    Session的活化和钝化

    • Session机制很好的解决了Cookie的不足,但是当访问应用的用户很多时,服务器上就会创建非常多的Session对象,如果不对这些Session对象进行处理,那么在Session失效之前,这些Session一直都会在服务器的内存中存在。那么,就出现了Session活化和钝化的机制。

    • **Session钝化:**Session在一段时间内没有被使用或关闭服务器时,会将当前存在的Session对象及Session对象中的数据从内存序列化到磁盘的过程,称之为钝化。

    • **Session活化:**Session被钝化后,服务器再次调用Session对象或重启服务器时,将Session对象及Session对象中的数据从磁盘反序列化到内存的过程,称之为活化。

    • 如果希望Session域中的对象也能够随Session钝化过程一起序列化到磁盘上,则对象的实现类也必须实现java.io.Serializable接口。不仅如此,如果对象中还包含其他对象的引用,则被关联的对象也必须支持序列化,否则会抛出异常:java.io.NotSerializableException

    浏览器和Session关联的技术内幕

    一旦浏览器关闭之后,我们再去获取Session对象就会创建一个新的Session对象。这是怎么回事呢。现在让我们来看一下。这一系列操作过程中的内幕细节。

    1558628349795

    通过上图的分析,我们不难发现。当浏览器关闭之后。只是因为浏览器无法再通知服务器,之前创建的Session的会话id是多少了。所以服务器没办法找到对应的Session对象之后,就以为这是第一次访问服务器。就创建了新的Session对象返回。

    Cookie

    • Session的实现原理中 : 每一个Seesion对象都会关联一个sessionid,例如 :

      • JSESSIONID=41C481F0224664BDB28E95081D23D5B8

      • 以上的这个键值对数据其实就是cookie对象。

      • 对于session关联的cookie来说,这个cookie是被保存在浏览器的 运行内存 当中。

      • 只要浏览器不关闭,用户再次发送请求的时候,会自动将运行内存的cookie发送给服务器。

      • 例如 , 这个cookie :

        JSESSIONID=41C481F0224664BDB28E95081D23D5B8就会再次发送给服务器。

      • 服务器就是根据41C481F0224664BDB28E95081D23D5B8这个值来找到对应的session对象的。

    • cookie怎么生成?cookie保存在什么地方?cookie有啥用?浏览器什么时候会发送cookie,发送哪些cookie给服务器???????

    • cookie最终是保存在浏览器客户端上面的。

      • 可以保存在运行内存中。(浏览器只要关闭cookie就会立即消失。)
      • 也可以保存在硬盘文件中。(永久保存)
    • cookie有什么用呢 ?

      • cookie和session的机制其实都为了保存绘画的状态。
      • cookie是将会话的状态保存在浏览器客户端上。(cookie数据存储在浏览器客户端上的。)
      • session是将会话的状态保存在服务器端上。(session对象是存储在服务器上。)
      • 为什么要有cookie和session机制呢?因为HTTP协议是无状态 无连接协议。

    经典案例

    • cookie的经典案例

      • 京东商城,在未登录的情况下,向购物车中放几件商品。然后关闭商城,再次打开浏览器,访问京东商城的时候,购物车中的商品还在,这是怎么做的?我没有登录,为什么购物车中还有商品呢?
    • 将购物车中的商品编号放到cookie当中,cookie保存在硬盘文件当中。这样即使关闭浏览器。硬盘上的cookie还在。下一次再打开京东商城的时候,查看购物车的时候,会自动读取本地硬盘中存储的cookie,拿到商品编号,动态展示购物车中的商品。

    • 京东存储购物车中商品的cookie可能是这样的:productIds=xxxxx,yyyy,zzz,kkkk

      • 注意:cookie如果清除掉,购物车中的商品就消失了。
    • cookie机制和session机制其实都不属于Java中的机制,其实cookie机制和session机制都是HTTP协议的一部分。不论是什么编程语言,cookie和session机制都时必不可少的。

    • HTTP协议中规定 : 任何一个cookie都是由name和value组成的。name和value都是字符串类型。

    • java的servlet中,对cookie提供了哪些支持呢?

      • 提供了一个Cookie类来专门表示cookie数据。javax.servlet.http.Cookie;
      • java程序怎么把cookie数据发送给浏览器呢?response.addCookie(cookie);
    • 在HTTP协议中是这样规定的:当浏览器发送请求的时候,会自动携带该path下的cookie数据给服务器。(URL。)

    • 关于cookie的有效时间

      • 怎么用Java设置cookie的有效时间
        • cookie.setMaxAge(60*60);设置保存在一小时之后失效。
      • 没有设置有效时间 : 默认保存在浏览器的运行内存中,浏览器关闭则cookie消失。
    • 只要设置cookie的有效时间 > 0,这个cookie一定会存储到硬盘文件当中。

    • 设置cookie的有效时间 = 0 呢?

      • cookie被删除,同名cookie被删除。
      • 设置cookie的有效时间 < 0 呢?
      • 保存在运行内存中。和不设置一样。
    • 浏览器发送cookie给服务器了,服务器中的java程序怎么接收?

    
    Cookie[] cookies = request.getCookies(); // 这个方法可能返回null
    
    if(cookies != null){
        for(Cookie cookie : cookies){
            // 获取cookie的name
            String name = cookie.getName();
            // 获取cookie的value
    
            String value = cookie.getValue();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Cookie的常用方法

    方法用途
    void setMaxAge(int age)设置Cookie的有效时间,单位为秒
    int getMaxAge()获取Cookie的有效时间
    String getName/()获取Cookie的name
    String getValue()获取Cookie的value

    Seesion与Cookie的区别

    Session: 保存在服务器,Session是一个对象保存在Java虚拟机中
    保存的数据是Object
    随着会话的结束而销毁
    保存重要信息

    Cookie: 保存在浏览器
    只能保存String类型,类似于文本文件,存放的都是数据,而不是对象
    可以长期保存在浏览器,与会话无关
    保存不重要信息

    存储用户信息:
    Session:setAttribute(name,“admin”) 存
    getAttribute(name) 取
    生命周期:服务端:只要WEB应用重启或者销毁
    客户端:只要浏览器关闭就销毁
    退出登录:session.invalidate();
    Cookie:
    Cookie cookie=new Cookie(name,“admin”);
    response.addCookie(cookie); 存

    取数据

    	Cookie[] cookies=request.getCookie();
     		for(Cookie cookie:cookies){
    				if(cookie.getName().equals("name"){
    						out.write("欢迎回来"+cookie.getValue());
    			}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    生命周期:不会随着服务端的重启而销毁,客户端:默认是只要关闭浏览器就会销毁,我们通过setMaxAge()方法来设置有效期,一旦设置了有效期,就不会随着浏览器的关闭而销毁,而是由设置的时间来决定
    退出登录:setMaxAge(0)

    Cookie是浏览器提供的一种技术,通过服务器的程序能把一些只须保存在客户端,或者在客户端进行处理的数据放在本地计算机上,不需要通过网络传送,因此提高网页处理效率,并且可以减少服务器的负载,但是因为Cookie是服务器端保存在客户端的信息,所以它的安全性也是很差的,例如:常见的记住密码就可以通过Cookie来实现

    如果想要把Cookie随着响应发送到客户端,需要先添加到response对象中

    cookie默认是关闭浏览器失效

    Cookie的有效时间值

    image-20220828202948622

    Cookie的注意点

    1.cookie保存在当前浏览器,不能跨浏览器,更不用说换电脑了
    2.cookie存中文问题
    cookie不能存中文,如果有中文,则通过URLEncoder.encode()来进行编码
    通过URLDecoder.decode()进行解码

    image-20220828203015097

    3.同名cookie问题
    如果服务器发送重复的cookie,那么会覆盖原来的cookie
    4.cookie的数量
    不同浏览器对cookie有限定,cookie的存储是有上限的,cookie存储在客户端(浏览器)的,而且一般是由服务器创建和指定,后期结合Session来实现会话追踪

    Cookie路径的问题

    Cookie的setPath(可以设置cookie的路径,这个路径直接决定服务器的请求是否会从浏览器中加载某些cookie

    情景一:当前服务器下的任何项目的任意资源都可以获取Cookie对象

    	//当前项目路径s
    	Cookie cookie=new Cookie("xxx","xxx");
    	//设置路径为"/",表示在当前项目下的任何项目都可以访问到cookie对象
    	
    	cookie.setPath("/");
     	response.addCookie(cookie);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    情景二:当前项目下的资源都可获取Cookie对象(默认不设置Cookie的path)

    当前项目路径s
    Cookie cookie=new Cookie("xxx","xxx");
    //设置路径为"/s",表示在当前项目下的任何项目都可以访问到cookie对象
    //默认情况下可以不设置path的值
    cookie.setPath("/s");
    response.addCookie(cookie);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    情景三:指定项目下的资源可获取Cookie对象

    当前项目路径s
    Cookie cookie=new Cookie("xxx","xxx");
    //设置路径为"/s2",表示在s2项目下才可以访问到
    cookie.setPath("/s2");
    //只能在s2项目下获取cookie,就算cookie是s产生的,s也不能获取它
     	response.addCookie(cookie);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    情景四:指定目录下的资源可获取Cookie对象

    //当前项目路径s
    Cookie cookie=new Cookie("xxx","xxx");
    //设置路径为/s/cook,表示在s1/cook目录下面才可以访问到cookie对象
    cookie.setPath("/s/cook");
    response.addCookie(cookie);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Cookie的禁用问题

    Cookie禁用了,session还能找到吗?

    cookie禁用就是说服务器正常发送cookie给浏览器,但是浏览器不要了。拒收了。并不是服务器不发了。
    找不到了。每一次请求都会获取到新的session对象。
    cookie禁用了,session机制还能实现吗?
    可以。需要使用URL重写机制。
    http://localhost:8080/servlet12/test/session;jsessionid=19D1C99560DCBF84839FA43D58F56E16
    URL重写机制会提高开发者的成本。开发人员在编写任何请求路径的时候,后面都要添加一个sessionid,给开发带来了很大的难度,很大的成本。所以大部分的网站都是这样设计的:如果禁用cookie,就别用了。

    URL重写(了解)

    • 在整个会话控制技术体系中,保持JSESSIONID的值主要通过Cookie实现。但Cookie在浏览器端可能会被禁用,所以我们还需要一些备用的技术手段,例如:URL重写。

    • URL重写其实就是将JSESSIONID的值以固定格式附着在URL地址后面,以实现保持JSESSIONID,进而保持会话状态。这个固定格式是:URL;jsessionid=xxxxxxxxx

    • 例如:

      targetServlet;jsessionid=97120112D5538009334F1C6DEADB1BE7
      
      • 1
    • 实现方式:

      • response.encodeURL(String)

      • response.encodeRedirectURL(String)

    • 示例代码

      //1.获取Session对象
      HttpSession session = request.getSession();
      		
      //2.创建目标URL地址字符串
      String url = "targetServlet";
      		
      //3.在目标URL地址字符串后面附加JSESSIONID的值
      url = response.encodeURL(url+";jsessionid=97120112D5538009334F1C6DEADB1BE7");
      		
      //4.重定向到目标资源
      response.sendRedirect(url);
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    处理表单重复提交问题

    • 表单重复提交的危害
      • 可重复注册,对数据库进行批处理攻击。(验证码已解决该问题)
      • 可重复提交已付款表单,用户支付一次订单费用,下了多个订单
      • 等待…
    • 解决表单重复提交的步骤
      • 生成一个不可重复(全球唯一)的随机数(uuid)
      • 在提交表单前,将随机数(uuid)分别存放到表单内的隐藏域,和session域对象中
      • 发送“提交表单”请求
      • 判断是否提交表单,具体操作如下:
        • 分别获取隐藏域和session域中的uuid
        • 判断两个域中的数据是否相等
          • 相等:提交表单,并将session域中的uuid移除
          • 不等:不提交表单
    • UUID
      • 定义:是一个32位16进制的随机数
      • 特点:全球唯一
      • 使用:java.util.UUID.randomUUID()
  • 相关阅读:
    “第六十二天”
    【ONE·Linux || 多线程(二)】
    sklearn机器学习——day14
    Go语言基础01 变量
    蓝桥杯B组C++省赛——飞机降落(DFS)
    用Vuex做共享,但Echarts不同步更新,如何更新dom
    easyswoole ORM 对于having 连贯操作
    图像分割-改进网络结构
    if...else绝佳替换方案
    【golang】调度系列之P
  • 原文地址:https://blog.csdn.net/qq_58608526/article/details/126592603