正确答案是:AddSession 默认不支持分布式,因其仅提供中间件壳子,不绑定存储;必须显式注册 IDistributedCache(如 Redis)并严格遵循配置顺序与安全设置。

不能直接用 AddSession + 内存缓存实现分布式会话 —— 多实例下必然丢数据、错乱、401。 真正能跑在生产集群里的方案,只有一条路:强制走 IDistributedCache 实现(如 Redis),且必须严格对齐配置和调用顺序。
为什么 AddSession 默认不支持分布式
ASP.NET Core 的 AddSession 本身只是中间件壳子,它不绑定存储;默认注册的 AddDistributedMemoryCache 是单机内存,各节点互不可见。哪怕你加了负载均衡,用户请求轮到不同机器,HttpContext.Session 读出来的就是空或旧值。
- 现象:登录后刷新页面突然登出、购物车商品随机消失、并发提交时
Session.SetString覆盖失效 - 根本原因:内存缓存无共享,Session ID 相同但后端数据完全隔离
- 误区:“只要用了
AddSession就算分布式”——其实只是“分布式的假象”
AddStackExchangeRedisCache 必须在 AddSession 之前注册
依赖注入容器里,AddSession 会尝试解析 IDistributedCache。如果 Redis 缓存服务没提前注册,它会 fallback 到内存实现,你完全感知不到失败。
- 正确顺序(
Program.cs):builder.Services.AddStackExchangeRedisCache(...)→builder.Services.AddSession(...) - 错误写法:把
AddSession放前面,或者漏掉 Redis 注册(NuGet 包Microsoft.Extensions.Caching.StackExchangeRedis必须安装) - 连接字符串必须指向同一 Redis 集群(不是每个节点连自己的 Redis 实例)
-
options.InstanceName建议设为固定前缀(如"prod_session:"),避免多环境 key 冲突
UseSession 的位置不能错,且必须配合 Cookie 安全设置
app.UseSession() 不是“随便放中间就行”,它依赖前面已解析的路由和认证上下文,也影响后续中间件能否读取 Session。
- 必须放在
app.UseRouting()之后、app.UseAuthentication()/app.UseAuthorization()之前 - Cookie 选项不设
IsEssential = true:某些浏览器(尤其启用了严格模式)会直接屏蔽 Session Cookie,导致HttpContext.Session为 null - 未设
HttpOnly = true或Secure = true(HTTPS 环境):可能被 XSS 窃取 Session ID - 超时时间(
IdleTimeout)建议显式设,不要依赖默认 20 分钟;Redis 中实际过期时间 = 滑动超时 + 5 分钟左右缓冲(由底层序列化机制决定)
Session 数据读写前必须 LoadAsync,否则可能为空
ASP.NET Core 的 Session 是懒加载的。即使 Cookie 里有有效 Session ID,HttpContext.Session 也不会自动从 Redis 拉数据 —— 你得手动触发。
- 典型错误:
HttpContext.Session.GetString("key")返回 null,但其实 Redis 里有值 - 修复方式:在读/写前加
await HttpContext.Session.LoadAsync()(推荐放在 Action 开头或全局 Filter) - 写操作(如
SetString)后需调用CommitAsync()才真正落库;不调用的话,下次请求仍读不到(尤其高并发场景下容易误以为“写成功了”) - 避免存大对象:Session 序列化用的是
System.Text.Json,复杂类型要确保可序列化;建议只存string、int、Guid等轻量标识,敏感字段(如手机号、token)坚决不进 Session
最易被忽略的一点:所有节点的 Cookie.Name、加密密钥(DataProtection 配置)、Redis 连接字符串、InstanceName 必须完全一致。差一个字符,就会出现“部分节点能登录、部分节点 401”的诡异问题,排查起来极耗时间。


















