zoukankan      html  css  js  c++  java
  • 聊聊cookie和session

    先参照:https://zhuanlan.zhihu.com/p/90750522

    ----2021.04.15

    最近公司的项目使用登录是cookie+redis,java项目服务器定义变量sessionId,sessionId=获取的cookie存放到redis上面去,我思考着,以前的服务器的session不是这样子的,于是我写了一个demo,demo很简单哈,自己创建springboot项目,然后创建controller就好了,现在开始调试并且源码的阅读:

    package com.example.com.test;

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;

    @RestController
    @RequestMapping("session")
    public class SessionTestController {
    @GetMapping("/setSession")
    public void setSession(HttpServletRequest request, HttpServletResponse response) throws IOException {
    request.getSession().setAttribute("user", "this is user");
    response.getWriter().write("设置session完成");
    }
    @GetMapping("getSession")
    public void getSession(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.getWriter().write("获取session为user"+request.getSession().getAttribute("user").toString());
    }
    }

      这里有几个问题:

    1.我们一直说的session到底是什么玩意?

    2.网上经常说cookie,那么session和cookie有什么联系

    3.怎么确认@GetMapping("/setSession")和@GetMapping("getSession")是同一个客户端呢?

    我们打断点开始

    1).用postman发送请求进入controller

    2.进入获取session的实现类,由于返回的是HttpSession,有好多个实现类

     3.进入RequestFacade子类,为什么进入的是这个类不是其它子类,我还没有看到相关源码,找到跟我讲一下

    4.接着调试


    --> 进入获取getsession方法
    public HttpSession getSession(boolean create) {
    if (this.request == null) {
    throw new IllegalStateException(sm.getString("requestFacade.nullRequest"));
    } else {
    return SecurityUtil.isPackageProtectionEnabled() ? (HttpSession)AccessController.doPrivileged(new RequestFacade.GetSessionPrivilegedAction(create)) : this.request.getSession(create);-- 关键看这个request.getsession()
    }
    }

     到目前为止:request的相关属性还是null, 如下图

     public HttpSession getSession(boolean create) {
            if (this.request == null) {
                throw new IllegalStateException(sm.getString("requestFacade.nullRequest"));
            } else {
                return SecurityUtil.isPackageProtectionEnabled() ? (HttpSession)AccessController.doPrivileged(new RequestFacade.GetSessionPrivilegedAction(create)) : this.request.getSession(create);进入这里
            }
        }
    

      

    5.查看this.request.getSession(create),目前已经进入Request类

      public HttpSession getSession(boolean create) {
            Session session = this.doGetSession(create); --这里是核心的代码
            return session == null ? null : session.getSession();
        }
    

    6.我们分析这个核心的代码

    protected Session doGetSession(boolean create) {
            Context context = this.getContext();
            if (context == null) {
                return null;
            } else {
           //这里判断,如果已经有session并且过期了,session赋值为null,但是我们这是第一次请求,session肯定是null,接着往下看 if (this.session != null && !this.session.isValid()) { this.session = null; } if (this.session != null) { return this.session; } else { Manager manager = context.getManager();--获取管理器,这个看看就好 if (manager == null) { return null; } else { if (this.requestedSessionId != null) { try { this.session = manager.findSession(this.requestedSessionId);--如果有值就去查找session,很显然第一次不会执行这里,这里点击进去在ManagerBase类会发现protected Map<String, Session> sessions = new ConcurrentHashMap();,也就是session是map的一个元素,服务器是用这个来保存的,第一个问题解决了
    } catch (IOException var14) { if (log.isDebugEnabled()) { log.debug(sm.getString("request.session.failed", new Object[]{this.requestedSessionId, var14.getMessage()}), var14); } else { log.info(sm.getString("request.session.failed", new Object[]{this.requestedSessionId, var14.getMessage()})); } this.session = null; } if (this.session != null && !this.session.isValid()) { this.session = null; } if (this.session != null) { this.session.access(); return this.session; } } if (!create) { return null; } else { boolean trackModesIncludesCookie = context.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.COOKIE); if (trackModesIncludesCookie && this.response.getResponse().isCommitted()) { throw new IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted")); } else { String sessionId = this.getRequestedSessionId(); if (!this.requestedSessionSSL) { if ("/".equals(context.getSessionCookiePath()) && this.isRequestedSessionIdFromCookie()) { if (context.getValidateClientProvidedNewSessionId()) { boolean found = false; Container[] var7 = this.getHost().findChildren(); int var8 = var7.length; for(int var9 = 0; var9 < var8; ++var9) { Container container = var7[var9]; Manager m = ((Context)container).getManager(); if (m != null) { try { if (m.findSession(sessionId) != null) { found = true; break; } } catch (IOException var13) { } } } if (!found) { sessionId = null; } } } else { sessionId = null; } } this.session = manager.createSession(sessionId); -- 这是创建session的id,插播里面的方法
                                if (this.session != null && trackModesIncludesCookie) {
                                    Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie(context, this.session.getIdInternal(), this.isSecure()); -- 这里是创建cookie的地方

     

                                    this.response.addSessionCookieInternal(cookie);
                                }
    
                                if (this.session == null) {
                                    return null;
                                } else {
                                    this.session.access();
                                    return this.session;
                                }
                            }
                        }
                    }
                }
            }
        }
    

      

    我们再去postman看看cookie,

      到这里,问题2.网上经常说cookie,那么session和cookie有什么联系,

    答案:我们的session的sessionId的值是服务器产生的,然后放到返回给前端cookie,cookie的name为JSESSION,value就是sessionId,我们第二次请求的时候会把这个JSESSIONID=89ECDF9A6C0D3EF30E4C3CF2BEEBD069给带过去,不信的话我再次发送

    这次可以请求为http://localhost:8081/household/session/getSession

     

    这个值应该是servlet规范帮你赋值到requestedSessionId,根据requestedSessionId去获取对应的session,这里也可以推断出

    问题3:怎么确认@GetMapping("/setSession")和@GetMapping("getSession")是同一个客户端呢?

    就是根据JSESSION的值去获取session,也就是requestedSessionId可以判断是否同一个客户端

    遗留一个问题:

     this.session = manager.findSession(this.requestedSessionId);那么我们创建session是什么时候放到这个map里面去的,我源码找不到哈


    ---解决了
    我们上面创建sessionId的时候,在setId的方法进行session存放



    public void add(Session session) { this.sessions.put(session.getIdInternal(), session); --这里put进去的 int size = this.getActiveSessions(); if (size > this.maxActive) { synchronized(this.maxActiveUpdateLock) { if (size > this.maxActive) { this.maxActive = size; } } } }

      



  • 相关阅读:
    Linux centos 安装php5.4和pthreads
    linux Nginx负载均衡
    linux 部署oracle 11g
    linux shell编程
    Linux 常 用 命 令
    python基础学习笔记的目录
    Python学习笔记之基础篇(-)python介绍与安装
    Python学习笔记之基础篇(二)python入门
    python 的logging 的配置,有这一篇就够了
    selenium+headless+proxy 的出错
  • 原文地址:https://www.cnblogs.com/imfjj/p/14477122.html
Copyright © 2011-2022 走看看