首页 > 其他分享 >Session 与 Cookie

Session 与 Cookie

时间:2023-06-13 14:01:21浏览次数:38  
标签:浏览器 Session session cookie Cookie public


评:



HTTP 协议 ( 超文本传输协议 ) 是无状态的,不能保存客户端与服务器之间通讯 ( 交互 ) 的信息。
打个比方,拿最常见的登录来说,现在好多网站的操作都需要用户登录,假如在 a 操作时,用户成功登录系统,再进行 b 操作时,由于 HTTP 协议是无状态的,
用户之前登录的信息并没有被记录下来。那么,用户需要再次登录系统才能继续操作,以此类推,每个操作都需要登录一次系统,这是非常可怕的事情。
cookie 和 session 技术的诞生,都是为解决 HTTP 无状态协议所带来的系列问题。它们可以维护用户与服务器间的会话状态。

Cookie

cookie 是保存在客户端的文本文件。在这个文本文件中以键值对 ( key - value ) 的形式保存了一些与用户相关的信息,如常见的有账号信息等。



package fan.commons.web;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
  * Cookie 操作
  * @Author fancy 
  * @Date 2013-09-29
  */
public class Cookies {
     
     private final HttpServletRequest request;
     private final HttpServletResponse response;
     
     public Cookies(final HttpServletRequest request, final HttpServletResponse response){
         this.request = request;
         this.response = response;
     }
     
     /**
      * 添加Cookie
      * @param cookie 实例
      */
     public void add(Cookie cookie){
         response.addCookie(cookie);
     }
     
     /**
      * 添加Cookie
      * @param name  名称
      * @param value 值
      */
     public void add(String name, String value){
         add(name, value, -1);
     }
     
     /**
      * 添加Cookie
      * @param name  名称
      * @param value 值
      * @param secondTimeout 设定多少秒后过期。若为负数, 则浏览器关闭后Cookie失效。
      */
     public void add(String name, String value, int secondTimeout){
         Cookie cookie = new Cookie(name, value);
         cookie.setMaxAge(secondTimeout);
         cookie.setPath("/");
         response.addCookie(cookie);
     }
     
     /**
      * 根据名称获取Cookie对象。如果不存在则返回null。
      * @param name 名称
      * @return 返回Cookie对象
      */
     public Cookie getCookie(String name){
         Cookie[] cookies = request.getCookies();
         if(cookies != null){
             for(Cookie cookie : cookies){
                 if(cookie.getName().equals(name)){
                     return cookie;
                 }
             }
         }
         return null;
     }
     
     /**
      * 根据名称获取Cookie对象的值。如果不存在则返回null。
      * @param name  名称
      * @return  返回该Cookie对象的值
      */
     public String getValue(String name){
         Cookie cookie = getCookie(name);
         return cookie == null ? null : cookie.getValue();
     }
     
     /**
      * 删除Cookie
      * @param name 名称
      */
     public void delete(String name){
         delete(new Cookie(name, null));
     }
     
     /**
      * 删除Cookie
      * @param cookie 需要删除的对象
      */
     public void delete(Cookie cookie){
         cookie.setMaxAge(0);  //0表示立即删除
        cookie.setPath("/");
         response.addCookie(cookie);
     }
     
     /**
      * 清空Cookie
      */
     public void clear(){
         Cookie[] cookies = request.getCookies();
         if(cookies != null){
             for(Cookie cookie : cookies){
                 delete(cookie);
             }
         }
     }
 } 
  
public  
   class CookieServlet  
   extends HttpServlet { 
   

      
   protected  
   void service(HttpServletRequest request, HttpServletResponse response) { 
   
         Cookies cookie =  
   new Cookies(request, response); 
   
          
   if(cookie.getValue("username") ==  
   null){ 
   
             cookie.add("username", "fancy"); 
   
         } 
   
          
   // 
   从客户端传递过来的 cookie 中获取信息 
   
        System.out.println(cookie.getValue("username")); 
   
     } 
   

 }

Session 与 Cookie_runtime



当客户端发起 http 请求时,相关的 cookie 信息将被放在 http 请求头 ( Request Headers ) 中,并发送至服务器端。


当服务器向客户端写回 ( 新建、更新、删除 ) cookie 时,这些 cookie 信息将被放到 http 响应头 ( Response Headers ) 中,并发回给客户端浏览器。


客户端浏览器接收并解析服务器发回的 cookie 信息,然后将它保存到文件或保存到内存当中。



Session 与 Cookie_System_02



Session 与 Cookie_客户端_03


Session

Session 是保存在服务器端,用于存放一些与用户相关的信息,如登录状态等。


Session 的创建时机

首先,Session 不是在客户机首次访问服务器时被创建的。


Session 的创建时机是当服务器端程序首次执行 HttpServletRequest.getSession() 或 HttpServletRequest.getSession(true) 时被创建的。


HttpServletRequest.getSession() 和 HttpServletRequest.getSession(true) 是等效的,


调这两个方法的时候,若 Session 已经存在,则直接返回使用。若不存在,则创建一个 Session 对象并返回使用。


HttpServletRequest.getSession(false) ,调用该方法的时候,若 Session 已经存在,则返回使用。若不存在,则返回 null。


下面借助 Session 监听器来监听 Session 的创建时机:

package fan.core.listener; 
   

import javax.servlet.http.HttpSessionEvent; 
   
import javax.servlet.http.HttpSessionListener; 
   

public  
   class SessionListener  
   implements HttpSessionListener { 
   
      
   
      
   public SessionListener(){ 
   
         System.out.println("*******************************"); 
   
         System.out.println("Startup SessionListener"); 
   
         System.out.println("*******************************"); 
   
     } 
   

      
   public  
   void sessionCreated(HttpSessionEvent e) { 
   
         System.out.println("*******************************"); 
   
         System.out.println("Create Session"); 
   
         System.out.println("*******************************"); 
   
     } 
   

      
   public  
   void sessionDestroyed(HttpSessionEvent e) { 
   
         System.out.println("*******************************"); 
   
         System.out.println("Destroy Session"); 
   
         System.out.println("*******************************"); 
   
     } 
   

 } 
   
  
public  
   class TestServlet  
   extends HttpServlet { 
   

      
   protected  
   void service(HttpServletRequest request, HttpServletResponse response) { 
   
         System.out.println("*******************************"); 
   
         System.out.println("TestServlet"); 
   
         System.out.println("*******************************"); 
   
     } 
   

 } 
   
  
< 
   listener 
   > 
   
    
   < 
   listener-class 
   >fan.core.listener.SessionListener 
   </ 
   listener-class 
   > 
   
</ 
   listener 
   > 
   

< 
   servlet 
   > 
   
   ...... 
   
</ 
   servlet 
   >


访问 TestServlet,发现控制台并没有打印出 "Create Session"。


修改 TestServlet 代码如下:


public  
   class TestServlet  
   extends HttpServlet { 
   

      
   protected  
   void service(HttpServletRequest request, HttpServletResponse response) { 
   
         request.getSession( 
   true); 
   
     } 
   

 }



再次访问该 TestServlet,控制台打印出 "Create Session"。



重启服务器,在浏览器中首次访问服务器中的任一 JSP 资源,发现控制台也打印出 "Create Session"。这是怎么回事呢?


是这样的,JSP 引擎在将 JSP 文件编译成类 Servlet 类文件 ( 该文件可以在 

%Tomcat%/work/%工程目录% 下找到 ) 时,还是打开 index_jsp.java 源码来对照着说吧:


Session 与 Cookie_System_04



可以看到源码中有一行 session = pageContext.getSession()。


这里的 pageContext 是 org.apache.jasper.runtime.PageContextImpl 的一个实例 ( 这个验证非常简单,有兴趣的可以动手试试 ),


打开 PageContextImpl 源码看一眼:



Session 与 Cookie_java_05



可以看到,JSP 默认的实现方式中去调了 HttpServletRequest.getSession() 方法,因此,当第一次访问某个 JSP 文件时,


如果服务器之前还没有为该用户创建过 Session,则会创建一个,而不管 Session 会不会被用到。


这里可以通过 <%@page session="false"%> 来关闭 JSP 中默认创建 Session 的行为。


当在 jsp 文件中设置 <%@page session="false"%>,访问这个 jsp 文件,如 index.jsp,那么再打开 index_jsp.java 文件,


发现 session = pageContext.getSession() 这一行不见了,控制台也没有打印出 "Create Session" 的字样。


JSESSIONID ( session cookie / sessionid )

同一时间里,服务器端存在许多 Session 对象。假如一个 Session 对象代表一个用户,那么,当某客户机请求服务器时,服务器如何知道哪个 Session 属于 哪个用户呢?


这是通过唯一标识 id 来识别的。服务器首先检查客户端请求里是否包含 session 标识,如果已经包含,说明服务器之前已经为该用户创建了 session,接着服务器根据这个 session 标识去检索对应的 session 对象。如果检索不到 (可能因为 session 过期已被销毁),则可能创建一个新的 session 对象 (HttpServletRequest.getSession(false) 的时候不创建)。如果客户端请求里不包含 session 标识,则创建一个新的 session 对象。服务器在创建 session 对象的时候会为每个 session 对象关联一个唯一的标识 sessionid,并将该标识的值以 cookie 的方式写回给客户端浏览器,保存在客户端浏览器内存中。当客户端再次向服务器发起请求时,根据 HTTP 协议,cookie 会被携带到服务器端,而 cookie 里面保存了一个能唯一标识用户自己身份的 sessionid,服务器端根据这个 id 就能找得到属于用户自己的 session 了。


从上面描述可以知道,session 是基于 cookie 机制来实现的,因此,上面所提到的 session 标识、sessionid 通常被称为 session cookie。我们平常时候所说的 cookie 被称为 persistent cookie。session cookie 是保存在客户端浏览器的内存当中,仅在本次会话中有效,当浏览器关闭之后,session cookie 也就失效并随之消失了。


cookie 是通过键值对 ( Key-Value ) 的形式来保存文本信息的,在 Java Web 运用中,session cookie 的键的名称为 JSESSIONID。看到 JSESSIONID,相信很多人都有一种亲切感,一般情况下,通常我们是看不到 JSESSIONID 的,因为它保存在 cookie 中,每次随请求默默的发送至服务器端。



修改 SessionListener 的 sessionCreated 方法:


public  
   void sessionCreated(HttpSessionEvent e) { 
   
     System.out.println("*******************************"); 
   
     System.out.println("Create Session, id = " + e.getSession().getId()); 
   
     System.out.println("*******************************"); 
   
 } 
   
  
public  
   class TestServlet  
   extends HttpServlet { 
   

      
   protected  
   void service(HttpServletRequest request, HttpServletResponse response) { 
   
         request.getSession( 
   true); 
   
     } 
   

 }


访问 TestServlet,结果如图:



Session 与 Cookie_runtime_06



public  
   class TestServlet  
   extends HttpServlet { 
   

      
   protected  
   void service(HttpServletRequest request, HttpServletResponse response) { 
   
         HttpSession session = request.getSession( 
   true); 
   
         System.out.println("[ Session ] " + session.getId()); 
   
         Cookies cookies =  
   new Cookies(request, response); 
   
         System.out.println("[ Cookies ] " + cookies.getValue("JSESSIONID")); 
   
     } 
   

 }



Session 与 Cookie_java_07



据说,在客户端禁用 cookie 的环境下,服务器会通过 URL 重写的方式,将 JSESSIONID 作为参数传递到服务器端。


本人不才,用了好些个浏览器禁用 cookie 几经折腾,并没有发现目标 URL 被重写,也没有发现请求参数中含有 JSESSIONID。什么情况? 


 Session 销毁的时机

当 session 有效期已过或服务器端程序调用了 HttpSession.invalidate(),则 session 对象被销毁,session 的内存空间也随之被 GC 收回。


客户端关闭浏览器时,存储在服务器端的 session 并不会被立刻销毁,直到 session 有效期过了,服务器才来销毁 session 对象。


Session 与浏览器的关系

根据上面对 JSESSIONID 的阐述,客户端浏览器每次请求服务器时,都会将能唯一识别用户 session 的 JSESSIONID 携带至服务器,以作为用户识别的身份凭据。


另外也知道,JSESSIONID 是保存在客户端浏览器的 cookie 文件中,存储在浏览器内存当中,其生命周期与浏览器相同。当多个浏览器请求同一台服务器时,在首次请求中,服务器发现这些浏览器都没有携带能标识用户 Session 的 JSESSIONID,因此,服务器分别为这些浏览器创建一个 Session 对象,并通过 HTTP 的响应头消息将 Session 的 id 以 cookie 的方式写回给客户端浏览器。因此,不同的浏览器所使用的 session 是不一样的 ( 这里只针对一般的情况 )。




标签:浏览器,Session,session,cookie,Cookie,public
From: https://blog.51cto.com/u_16080829/6469316

相关文章

  • [ABC305C] Snuke the Cookie Picker题解
    题目大意有一个\(H\timesW\)的网格,一种有一个矩形,矩形中间有一个点被挖空,求这个点的坐标。(.表示空白,#表示矩形内的点)解析观察我们可以发现,每一矩形内的个点上下左右至少会有两个是#。如图:而每一个在矩形外的点上下左右最多只有一个#。所以我们只需要找的一个.的上......
  • Java 实战介绍 Cookie 和 Session 的区别
    HTTP是一种不保存状态的协议,即无状态协议,HTTP协议不会保存请求和响应之间的通信状态,协议对于发送过的请求和响应都不会做持久化处理。无状态协议减少了对服务压力,如果一个服务器需要处理百万级用户的请求状态,对服务器的压力无疑的是巨大的。无状态的HTTP由于其简单和易用性......
  • 数据存储的两种方式:cookie和webStorage存储
    一、sessionstorage(会话存储)1、添加数据:SessionStorage.setItem('key','value');该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。2、获取数据:SessionStorage.getItem('key');该方法接受一个键名作为参数,返回键名对应的值。如果获取不到......
  • git问题:remote: [session-584b73b2] Access denied... The requ ested URL returned e
     error403是服务器拒绝了终端的访问,是账户密码的问题,是因为git客户端缓存了错误的密码。我是原来有个git账户,使用https方式,密码永久保存的方式,在操作另一个git账户时可能更新了缓存密码。方法:使用gitclonehttp://username:[email protected]/name/projectname.git克隆任......
  • 远程线程注入之突破Session0隔离会话
    前言当我们使用远程线程注入将dll注入至系统服务进程中往往会失败,这是因为大多数系统服务都是在Session0中运行的"Session0"是Windows操作系统中的一个特殊的会话,专门用于运行系统服务和其他在用户登录之前就需要运行的程序。从WindowsVista和WindowsServer2008开始,为了提高......
  • vue之elementui使用, vuex使用, Router使用, localstorage和sessionstorage,和cookie
    目录一、elementui使用下载插件vue界的ui库二、vuex的使用1.概念2.何时使用?3、使用步骤:三、Router使用1简单使用2组件中实现页面跳转3路由跳转时,可以使用对象4this.router的一些方法四、多级路由五、路由守卫和两种工作模式路由守卫路由器的两种工作模式六、localstorage和se......
  • Axios 代理跨域后后端无法接收Session问题
    将一个MVC项目重构为一个前后端分离项目,前端使用了react+axios+vite...。在前后端分离项目中,通常都会使用代理来解决跨域问题,vite需要在vite.config.js文件中配置代理:exportdefaultdefineConfig({server:{//代理配置proxy:{//请求前缀......
  • cookie 和session的区别
    1、对象不同cookie:是针对每个网站的信息,每个网站只能对应一个,其他网站无法访问,这个文件保存在客户端,每次您拨打相应网站,浏览器都会查找该网站的cookies,如果有,则会将该文件发送出去。cookies文件的内容大致上包括了诸如用户名、密码、设置等信息。session:是针对每个用户的,只有客......
  • nginx+tomcat+memcached (msm)实现 session同步复制
    这里重点强调如何实现linux服务器上服务器session共享,软件安装不再赘述。 首先我们需要对cookie和session的工作机制非常了解,如果不了解其中的原理,就算配置成功,也毫无意义。换了工作换了环境,重新配置起来 仍然需要重头来过,事倍功半。    cookie是怎样工作的? 例如,我们创......
  • CInternetSession(获取网页源码)
    CObject└CInternetSession使用类CInternetSession创建并初始化一个或多个同时的Internet会话。如果需要,还可描述与代理服务器的连接。如果Internet连接必须在应用过程中保持着,可创建一个类CWinApp的CInternetSession成员。一旦已建立起Internet会话,就可调用OpenUR......