1. Cookie与Session的本质区别
第一次接触Web开发时,我也曾被Cookie和Session的概念困扰过。直到有次线上事故——用户登录状态莫名丢失,排查到凌晨三点才发现是Session超时设置不当。这个惨痛教训让我彻底搞懂了这对"兄弟"的差异。
Cookie本质是客户端存储机制。当服务器通过Set-Cookie头部下发数据后,浏览器会将其以文本形式保存在本地。下次请求时自动通过Cookie头部回传,就像去咖啡店时店员给你一张积分卡(Cookie),下次出示就能识别身份。
Session则是服务端状态管理方案。服务器为每个会话创建唯一的Session ID(通常通过Cookie传递),实际用户数据存储在服务端内存或数据库中。相当于咖啡店给你一张会员卡号(Session ID),他们根据这个号码在系统里查询你的详细资料。
关键区别:Cookie数据存储在客户端,Session数据存储在服务端。这就决定了Cookie有大小限制(通常4KB)、存在安全风险但节省服务器资源;Session能存更多数据更安全但增加服务器负担。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Spring中的实现机制
2.1 Cookie操作实战
在Spring中操作Cookie简单到令人发指。比如实现"最近浏览商品"功能:
java复制// 写入Cookie
@GetMapping("/product/{id}")
public String viewProduct(@PathVariable String id, HttpServletResponse response) {
Cookie cookie = new Cookie("recent_view", id);
cookie.setMaxAge(30 * 24 * 60 * 60); // 30天有效期
cookie.setPath("/"); // 全站有效
cookie.setHttpOnly(true); // 防XSS
response.addCookie(cookie);
return "product";
}
// 读取Cookie
@GetMapping("/cart")
public String viewCart(@CookieValue(name = "recent_view", defaultValue = "") String recentProduct) {
System.out.println("最近浏览:" + recentProduct);
return "cart";
}
几个容易踩坑的点:
- Chrome 80+版本要求设置
SameSite属性防止CSRF攻击 - 敏感信息必须设置
Secure+HttpOnly双重保护 - 中文需要URL编码处理:
URLEncoder.encode("值","UTF-8")
2.2 Session深度解析
Spring Boot自动配置了Session管理器,默认使用内存存储。在控制器中可以直接使用:
java复制@PostMapping("/login")
public String login(HttpSession session, @RequestParam String username) {
session.setAttribute("user", username);
session.setMaxInactiveInterval(1800); // 30分钟超时
return "dashboard";
}
生产环境推荐改用Redis持久化Session,只需添加依赖:
xml复制<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
然后在application.properties配置:
properties复制spring.session.store-type=redis
spring.redis.host=127.0.0.1
3. 安全攻防实战
3.1 Cookie安全加固
去年我们系统遭遇过一次Cookie劫持攻击,黑客通过WiFi嗅探获取用户Cookie。解决方案是:
- 全站启用HTTPS
- 关键Cookie添加属性:
java复制cookie.setSecure(true); // 仅HTTPS传输 cookie.setHttpOnly(true); // 禁止JS访问 cookie.setSameSite("Strict"); // 禁止跨站发送
3.2 Session固定攻击防护
攻击者先获取自己的Session ID,诱导用户使用该ID登录。Spring Security默认已防护,手动实现可以:
java复制@Configuration
public class SessionConfig implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
se.getSession().invalidate(); // 强制创建新Session
}
}
4. 性能优化技巧
4.1 Session序列化优化
默认Java序列化性能差,改用JSON序列化:
java复制@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
4.2 分布式Session方案
当集群部署时,推荐组合方案:
- 使用Spring Session + Redis保证一致性
- 对频繁访问的数据添加本地缓存:
java复制@Cacheable(value = "sessionCache", key = "#session.id") public UserData getSessionData(String sessionId) { // 从Redis获取 }
5. 常见问题排雷
Q:用户反映登录状态随机丢失
- 检查服务器时钟是否同步(NTP服务)
- 确认负载均衡配置了会话保持(Sticky Session)
- 排查Redis内存是否不足导致Key被清除
Q:Cookie在子域名不共享
- 设置domain为父域名:
.example.com - 注意:开头必须有点号!
Q:Session并发修改报错
- 对写操作加锁:
java复制synchronized(session.getId()) { session.setAttribute("cart", cart); }
6. 前沿趋势观察
最新的Spring Security 6.0开始推荐无状态JWT方案,但对于传统Web应用,Cookie+Session仍是主流。最近帮某电商平台做架构升级时,我们采用混合方案:
- 高频操作使用JWT减少服务端压力
- 敏感操作仍走Session保证可注销性
实际测试显示,这种混合模式比纯JWT方案减少30%的Redis负载,同时保持安全性。具体实现可以参考我的GitHub示例项目(注:此处应替换为实际项目链接)。
