Session丢失

前言

在搭建完集群环境后,不得不考虑的一个问题就是用户访问产生的session如何处理。如果不做任何处理的话,用户将出现频繁登录的现象,比如集群中存在A、B两台服务器。

用户第一次访问网站时,Nginx通过其负载均衡机制将用户请求转发到A服务器,这时A服务器就会给用户创建一个Session。当用户第二次发送请求时,Nginx将其负载均衡到B服务器,而这时候B服务器并不存在Session,所以就会将用户踢到登录页面。

这将大大降低用户体验度,导致用户的流失,这种情况是项目绝不应该出现的。

模拟Session丢失的情况

先配置nginx

配置nginx,为了方便就用Windows的nginx
在这里插入图片描述
每次访问nginx的80端口即可

模拟代码:将这个数据存到Session中

@RestController
public class MyController {

    @Value("${server.port}")
    int port;

	//模拟登陆
    @RequestMapping("/login")
    public String login(HttpSession session){
        session.setAttribute("name","tom");
        return port+": login:"+session.getAttribute("name");
    }
	
	//模拟登录后直接从session里面获取信息
    @RequestMapping("/test")
    public String test(HttpSession session){
        return port+": test:"+session.getAttribute("name");
    }
}

复制一份springboot程序

然后准备8080和8081两个端口的服务器来进行访问
在这里插入图片描述
登陆,可以看到我们是从8081端口登陆,在实际情况下我们8081和8080端口部署了相同的项目,就是一个小的分布式集群,第一次访问网站时,Nginx通过其负载均衡机制将用户请求转发到8081服务器,这时8081服务器(在响应头中)就会给用户创建一个Session。如下是SessionId
在这里插入图片描述
但是当我们执行test方法的时候,他是进的8080端口并且name变成了null,而且SessionId变了,这是因为我们8080端口拿不到8081端口所创建的Session的信息,8080也没有执行它的login所以它的name属性就为null,并且重新给你创建了一个SessionId(可以发现两次SessionId不一样)
在这里插入图片描述
但是当我们在执行test方法就跳到了8081端口的test方法,这时候8081的name也为null
在这里插入图片描述
可以对应下面这个图进行理解,可以对应我们文章开头的前言进行理解
在这里插入图片描述

解决方法

我们使用Spring-Session来进行处理,Spring-Session实现原理就是讲session存储到redis中,不存在每个服务器的tomcat中。

导入依赖

<!--Spring-Session依赖-->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
<!--Spring-Session依赖-->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

application.properties配置文件

spring.redis.host=192.168.195.157
spring.redis.port=6379
spring.redis.password=123
spring.redis.database=0
spring.redis.jedis.pool.max-active=20
spring.redis.jedis.pool.max-idle=10
server.port=${port:8080}

Controller方法

@RestController
public class MyController {

    @Value("${server.port}")
    int port;

    @RequestMapping("/login")
    public String login(HttpSession session){
        session.setAttribute("name","tom");
        return port+": login:"+session.getAttribute("name");
    }
    @RequestMapping("/test")
    public String test(HttpSession session){
        return port+": test:"+session.getAttribute("name");
    }
}

启动类
核心就是加这个@EnableRedisHttpSession注解

@EnableRedisHttpSession//这个是将Session信息存入redis中,也是我们解决Session丢失的关键
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

执行结果:

8081:login
在这里插入图片描述
8080:test
在这里插入图片描述
8081:test
在这里插入图片描述
redis也是过期时间30分钟,跟我们tomcat服务器存储session时间是一样的
在这里插入图片描述

我们可以清楚的看到不论是我们只需8081服务端的test方法还是8081服务端的方法SessionId均没有变化、Session里面的name信息也没有变化,这就解决了Session丢失的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值