MZY项目笔记:session歧路

 

from my typora

MZY项目笔记:session歧路

以前对session的理解不够透彻,今天跪着来补。

前因是因为项目问题:

在浏览器中,一个浏览器多次请求默认状态下只会有一个sessionId,但是当两边都是服务端的时候,每次重复请求,此时会被服务端当成不同的请求来处理!

前后台分离之后,前后台运行在不同的容器上,每次前端请求都会被后台认为是一次新的会话,在后台输出当前的sessionId发现,每次的sessionId都不一样,所以这种情况下没法做登录和数据接口的权限过滤操作。

那该怎么办?

开始了漫长的尝试歧路。

1. 手动加上cookie的header。

在第一次登录的时候,服务端把sessionId带给前端,前端把sesionId存到一个变量中。

在之后ajax的时候,提前加上cookie的header,把sessionId手动传上去,这样是不是就能让服务器识别,找到对应的会话了?

$.ajax({
    xhrFields: {  
        withCredentials: true  
    },
    type: "GET",
    url:"http://localhost:8080/getData",
    beforeSend: function(request) {
        // request.setRequestHeader("JSESSIONID", JSESSIONID);
        // request.setRequestHeader("Set-Cookie", JSESSIONID);
        request.setRequestHeader("Cookie", "JSESSIONID="+JSESSIONID);
    },
    dataType:"json",
    success: function(msg) {
        console.log(msg);	
    }
});	

400、bad request

以上都是不行的,在w3c的标准中直接就不允许:

以下转自的噢可爱滴蓝晶晶的CSDN:

w3c规定,当请求的header匹配以下不安全字符时,将被终止

Accept-Charset
Accept-Encoding
Connection
Content-Length
Cookie
Cookie2
Content-Transfer-Encoding
Date
Expect
Host
Keep-Alive
Referer
TE
Trailer
Transfer-Encoding
Upgrade
User-Agent
Via

2.自己模拟一个SessionContext。

在的SIHAIloveYAN的CSDN上看到了模拟session容器的文章:

// 以下是我的SpringBoot中的测试:

// 创建一个自己的SessionContext
package club.mzywucai.cros_session_model.domain;

import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import java.util.HashMap;

/**
 * @author mzywucai
 * @Description
 * @date 2018/12/10
 */
public class SessionContext {

    private static HashMap sessionMap = new HashMap();

    public static synchronized void AddSession(HttpSession session) {
        if (session != null) {
            sessionMap.put(session.getId(), session);
        }
    }

    public static synchronized void DelSession(HttpSession session) {
        if (session != null) {
            sessionMap.remove(session.getId());
        }
    }

    public static synchronized HttpSession getSession(String session_id) {
        if (session_id == null)
            return null;
        return (HttpSession) sessionMap.get(session_id);
    }
}

// 创建一个监听器,每次session创建就add,session销毁就remove,防止内存泄漏
package club.mzywucai.cros_session_model.listener;

import club.mzywucai.cros_session_model.domain.SessionContext;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * @author mzywucai
 * @Description
 * @date 2018/12/10
 */
@WebListener
public class SessionListener implements HttpSessionListener {

    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        SessionContext.AddSession(httpSessionEvent.getSession());
    }

    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        HttpSession session = httpSessionEvent.getSession();
        SessionContext.DelSession(session);
    }
}


但是这样就能解决了吗?现在前端访问后台我就能把session对应起来了吗?

如果我多次请求的话,多个session不就在内存里面炸了?我新请求一次,create一个session;虽然我从context中拿到了想要的session,但是同时岂不是也压入了很多没用的session?

原来servlet中的session不一定会被创建,我居然今天才知道。

就在我想这个问题的时候,我得知了一个惊天的大秘密!(所以我就加粗斜体写了😀)

原来,只要我们不注入session就不会创建session!!!

回想起最初学servlet的时候,通过request拿到session的时候,是通过request.getSession(),getSession中有个boolean类型的参数:

getSession(true):

​ 当内存中不存在session的时候就创建session。

getSession(false):

​ 当内存中不存在session的时候就拿不到session(故此时的会话并不会创建session);

session的使用,其实是建立在一种假设用户回访才会使用的!!

果然知识需要回顾,不然这种简单的都会忘记

3.引入token机制

得到启发的帖子

这下大问题就真的没有了,我只在登录的时候,创建一个session,把登录的sessionId和一些关键信息加密组合作为token给前台并放入我的SessionContext中,后面的每次会话都是取现有的session,都不会再进行session的创建动作了(注意不要再在其它地方随便创建session了,因为前后台分离造成每次请求都是一次新的会话,会造成内存泄漏)!

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8" />
      <title>token测试</title>
      
   </head>
   <script src="js/jQuery_3.3.1.js"></script>
      <script type="text/javascript">
         var token;
         $(document).ready(function(){
            $("#getData").click(function(){
               alert("click");
               
               $.ajax({                  
                  type: "GET",
                  url:"http://localhost:8080/getData",
                  beforeSend: function(request) {
                     request.setRequestHeader("Authorization", token);
                            console.log(token);                     
                         },
                  dataType:"json",
                  success: function(msg) {
                     console.log(msg);   
                  }
               });   
            });
            
            $.ajax({
               type: "POST",
               url:"http://localhost:8080/login",
               data: "username=mzy&password=123",
               dataType:"json",
               success: function(msg) {
                  JSESSIONID = msg.data;
                  if (msg.code == 0) {
                     token = msg.data;   
                  }
                  
                  console.log("token="+token);   
               }
            });   
            
         });
      </script>
   <body>
      <button id="getData">获取数据</button>
   </body>
</html>

可以看到操作成功!


通过以上就可以把session存在我自己的容器里面,但是其实还是比较耗内存,因为这样需要把session在内存中存两份,服务器内置容器中一份,我自己的容器中一份。这个问题留着后面解决。

posted @ 2018-12-11 17:40  五彩世界  阅读(277)  评论(0编辑  收藏  举报