聊聊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; } } } }

  



原文地址:https://www.cnblogs.com/imfjj/p/14477122.html