ASP.NET Core 6.0中并发请求与会话状态计数异常问题
问题分析与解决方案
你的代码在并发请求下计数混乱,核心有两个原因:
- Session修改延迟持久化:ASP.NET Core默认会在请求结束时才将Session的修改写入后端存储(即使是内存存储)。你在lock块里修改了Session,但lock释放后,修改还没同步到共享存储,后续请求进入lock时读取的依然是旧值,导致多个请求拿到相同的计数并递增。
- 分支逻辑遗漏返回结果:当
subscriptionCount为null时,你设置计数为1后没有返回任何IActionResult,这会导致请求返回204 No Content,同时可能延长Session修改的提交时机。
修正后的代码
private readonly static object _lockObj = new(); public IActionResult Subscribe() { lock (_lockObj) { int? subscriptionCount = HttpContext.Session.GetInt32("SubscriptionCount"); if (subscriptionCount == null) { HttpContext.Session.SetInt32("SubscriptionCount", 1); // 立即提交Session修改,确保后续请求能读取到最新值 HttpContext.Session.Commit(); return Ok(new { Result = "Created" }); } else { if (subscriptionCount > 10) { return StatusCode(StatusCodes.Status403Forbidden, new { Result = "Max subscriptions per user/session reached" }); } else { subscriptionCount++; HttpContext.Session.SetInt32("SubscriptionCount", subscriptionCount.Value); Console.WriteLine($"SubscriptionCount={subscriptionCount}"); // 立即提交Session修改 HttpContext.Session.Commit(); return Ok(new { Result = "Created" }); } } } }
关键改进说明
- 立即提交Session:调用
HttpContext.Session.Commit()强制将Session的修改同步到共享存储,确保后续请求进入lock时能读取到最新的计数。 - 完善分支返回逻辑:在
subscriptionCount为null的分支添加return Ok(...),保证请求返回预期结果,同时避免Session提交延迟。 - 保留static锁:
_lockObj是静态的,确保进程内所有请求都能通过这个锁同步,避免并发修改计数。
分布式场景补充(可选)
如果你的应用部署在多服务器或多进程环境下,static锁无法跨进程同步,此时需要:
- 使用分布式Session存储(如Redis)
- 配合分布式锁(如Redis锁)来替代static锁,确保跨进程的计数同步。
内容的提问来源于stack exchange,提问作者Suresh Kumar
相关产品推荐
相关产品推荐

