**摘要**  
在Web应用中,用户会话管理是保障系统安全与性能的关键。本文将通过一个完整的实战案例,介绍如何使用Spring Boot、Vue.js和Redis实现高并发场景下的会话管理,包括会话存储、过期策略、分布式一致性等核心问题,并提供可落地的代码示例。

---

### **一、背景与问题分析**
传统基于Servlet Session的会话管理在单体应用中表现良好,但在分布式环境下存在以下问题:
- 会话无法跨服务共享
- 内存存储易丢失,且扩展性差
- 高并发下会话读写可能成为性能瓶颈

本文提出使用Redis作为分布式会话存储,结合Spring Session和Vue前端配合实现无状态会话管理。

---

### **二、技术栈与版本**
- 后端:Spring Boot 3.1.5、Spring Security 6、Spring Session Data Redis
- 前端:Vue 3 + Pinia + Axios
- 中间件:Redis 7.x(支持JSON序列化)
- 依赖管理:Maven

---

### **三、后端实现:Spring Boot整合Redis Session**

#### **1. 添加依赖**
```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
```

#### **2. 配置Redis与Session**
```yaml
# application.yml
spring:
  data:
    redis:
      host: localhost
      port: 6379
      password:
      database: 0
  session:
    timeout: 1800  # 30分钟过期
    redis:
      flush-mode: on_save
      namespace: spring:session
```

#### **3. 自定义会话配置类**
```java
@Configuration
@EnableRedisHttpSession
public class SessionConfig {
    
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }
    
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        serializer.setCookieName("JSESSIONID");
        serializer.setCookiePath("/");
        serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
        return serializer;
    }
}
```

#### **4. 会话控制Controller示例**
```java
@RestController
@RequestMapping("/api/session")
public class SessionController {
    
    @GetMapping("/info")
    public ResponseEntity<Map<String, Object>> getSessionInfo(HttpSession session) {
        Map<String, Object> data = new HashMap<>();
        data.put("sessionId", session.getId());
        data.put("creationTime", new Date(session.getCreationTime()));
        data.put("lastAccessedTime", new Date(session.getLastAccessedTime()));
        data.put("maxInactiveInterval", session.getMaxInactiveInterval());
        data.put("attributes", session.getAttributeNames());
        return ResponseEntity.ok(data);
    }
    
    @PostMapping("/set")
    public ResponseEntity<String> setAttribute(
            @RequestParam String key, 
            @RequestParam String value, 
            HttpSession session) {
        session.setAttribute(key, value);
        // 设置Redis中该会话的独立过期时间(示例:10分钟)
        session.setMaxInactiveInterval(600);
        return ResponseEntity.ok("属性设置成功");
    }
}
```

---

### **四、前端实现:Vue3管理会话状态**

#### **1. 安装依赖**
```bash
npm install pinia axios js-cookie
```

#### **2. 会话状态管理(Pinia)**
```javascript
// stores/sessionStore.js
import { defineStore } from 'pinia';
import axios from 'axios';
import Cookies from 'js-cookie';

export const useSessionStore = defineStore('session', {
  state: () => ({
    sessionId: '',
    userInfo: null,
    lastActivity: null
  }),
  
  actions: {
    // 获取会话信息
    async fetchSessionInfo() {
      try {
        const response = await axios.get('/api/session/info', {
          withCredentials: true
        });
        this.sessionId = response.data.sessionId;
        this.lastActivity = response.data.lastAccessedTime;
        return response.data;
      } catch (error) {
        console.error('获取会话信息失败:', error);
        this.clearSession();
      }
    },
    
    // 设置会话属性
    async setSessionAttribute(key, value) {
      const formData = new FormData();
      formData.append('key', key);
      formData.append('value', value);
      
      await axios.post('/api/session/set', formData, {
        withCredentials: true,
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
      });
      
      if (key === 'userInfo') {
        this.userInfo = value;
      }
    },
    
    // 清除会话
    clearSession() {
      this.sessionId = '';
      this.userInfo = null;
      this.lastActivity = null;
      Cookies.remove('JSESSIONID', { path: '/' });
    },
    
    // 会话保活(每5分钟发送一次请求)
    startKeepAlive() {
      setInterval(async () => {
        if (this.sessionId) {
          await this.fetchSessionInfo();
        }
      }, 5 * 60 * 1000);
    }
  },
  
  getters: {
    isSessionActive: (state) => {
      return !!state.sessionId && 
        (Date.now() - new Date(state.lastActivity).getTime()) < 30 * 60 * 1000;
    }
  }
});
```

#### **3. 全局拦截器配置**
```javascript
// utils/axiosInterceptor.js
import axios from 'axios';
import { useSessionStore } from '@/stores/sessionStore';

axios.interceptors.request.use(config => {
  const sessionStore = useSessionStore();
  if (sessionStore.sessionId) {
    config.headers['X-Session-ID'] = sessionStore.sessionId;
  }
  config.withCredentials = true;
  return config;
});

axios.interceptors.response.use(
  response => response,
  error => {
    if (error.response?.status === 401) {
      const sessionStore = useSessionStore();
      sessionStore.clearSession();
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);
```

---

### **五、Redis高级配置与会话优化**

#### **1. Redis配置文件优化**
```bash
# redis.conf 关键配置
maxmemory 1gb
maxmemory-policy allkeys-lru
save 900 1
save 300 10
save 60 10000
```

#### **2. 会话监控与统计**
```java
@Service
public class SessionMonitorService {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    // 获取当前活跃会话数
    public long getActiveSessionCount() {
        Set<String> keys = redisTemplate.keys("spring:session:sessions:*");
        return keys == null ? 0 : keys.size();
    }
    
    // 清理过期会话
    public void cleanExpiredSessions() {
        redisTemplate.execute((RedisCallback<Long>) connection -> {
            long deleted = 0;
            Cursor<byte[]> cursor = connection.scan(
                ScanOptions.scanOptions()
                    .match("spring:session:sessions:*")
                    .count(100)
                    .build()
            );
            while (cursor.hasNext()) {
                byte[] key = cursor.next();
                Long ttl = connection.ttl(key);
                if (ttl != null && ttl < 0) {
                    connection.del(key);
                    deleted++;
                }
            }
            return deleted;
        });
    }
}
```

---

### **六、测试方案**

#### **1. 单元测试(会话服务)**
```java
@SpringBootTest
class SessionServiceTest {
    
    @Autowired
    private SessionMonitorService sessionService;
    
    @Test
    void testSessionOperations() {
        HttpSession session = new MockHttpSession();
        session.setAttribute("testKey", "testValue");
        assertEquals("testValue", session.getAttribute("testKey"));
    }
}
```

#### **2. 压力测试(JMeter配置)**
- 线程组:500并发用户
- 循环次数:100
- 测试接口:/api/session/set 和 /api/session/info
- 监控指标:响应时间、吞吐量、Redis内存使用

---

### **七、部署与运维建议**

#### **1. Docker部署Redis集群**
```dockerfile
# docker-compose.yml 片段
version: '3.8'
services:
  redis-master:
    image: redis:7-alpine
    command: redis-server --requirepass yourpassword
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data

  redis-slave:
    image: redis:7-alpine
    command: redis-server --slaveof redis-master 6379 --requirepass yourpassword
    depends_on:
      - redis-master
```

#### **2. 监控告警配置**
- 使用Spring Boot Actuator监控会话相关指标
- 配置Redis内存使用率告警(阈值>80%)
- 日志集中收集(ELK Stack)

---

### **八、总结与扩展**

本文实现的Redis会话管理方案具有以下优势:
1. **高可用**:支持Redis主从复制与集群模式
2. **高性能**:内存读写,支持高并发场景
3. **可扩展**:无缝支持服务横向扩展
4. **灵活过期策略**:支持全局与会话级过期时间

**扩展方向**:
1. 集成JWT实现混合认证
2. 会话数据加密存储
3. 基于地理位置的会话管理
4. 实时会话监控大屏

---

**参考文献**:
1. Spring官方文档 - Spring Session
2. Redis官方文档 - 持久化与复制
3. Vue3官方文档 - 状态管理

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐