ASP.NET Core Session值无法持久化问题求助
ASP.NET Core Session值无法持久化问题分析与解决
问题原因
1. 多请求并行导致Session ID冲突
当isAjaxRequest = false时,页面加载时的并行请求(页面HTML请求 + /api/shopping-cart/cart接口请求)都会触发自定义SessionMiddleware的逻辑:
- 首次访问时两个请求都未携带Session Cookie,ASP.NET Core会为每个请求生成独立的Session ID,同时各自写入
VisitorGUID到Session中。 - 客户端会先后收到两个响应的
.AspNetCore.SessionCookie,后到达的Cookie会覆盖先到达的,导致API请求创建的包含ShoppingCartGuid的Session被丢弃。 - 页面刷新时,客户端携带的是最后保存的Session ID,自然无法找到之前API请求写入的
ShoppingCartGuid。
2. Session操作范围未精准过滤
自定义SessionMiddleware的设计目标应为页面请求设置访客标识,但未正确排除AJAX/API请求。当无关请求也执行Session写入操作时,会在无Session ID的场景下创建独立Session,导致页面与API请求的Session数据无法共享。
解决思路
1. 精准过滤AJAX/API请求
修复isAjaxRequest的判断逻辑,结合请求头和路径排除API/AJAX请求,避免其触发Session写入:
public async Task InvokeAsync(HttpContext context) { var excludedExtensions = new[] { ".css", ".js", ".png", ".jpg", ".gif" }; var pathValue = context.Request.Path.Value?.ToLower(); var queryValue = context.Request.QueryString.Value; // 正确识别AJAX请求(前端库如jQuery、Axios默认携带X-Requested-With头) var isAjaxRequest = context.Request.Headers.TryGetValue("X-Requested-With", out var headerValue) && headerValue.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase); // 识别API路径请求 var isApiRequest = context.Request.Path.StartsWithSegments("/api"); if ((string.IsNullOrEmpty(queryValue) || !queryValue.Contains("handler=")) && !isAjaxRequest && !isApiRequest && (pathValue == null || !excludedExtensions.Any(ext => pathValue.EndsWith(ext)))) { // 原有的Cookie检查和Session写入逻辑 Guid parsedGuid; if (!context.Request.Cookies.TryGetValue("CustomClosetsVisitorGUID", out var visitorGuid) || string.IsNullOrWhiteSpace(visitorGuid) || !Guid.TryParse(visitorGuid, out parsedGuid)) { visitorGuid = Guid.NewGuid().ToString(); } context.Response.Cookies.Append("CustomClosetsVisitorGUID", visitorGuid, new CookieOptions { Expires = DateTimeOffset.Now.AddDays(30) // 设置明确过期时间,避免会话Cookie丢失 }); context.Session.SetString("VisitorGUID", visitorGuid); } await _next(context); }
2. 避免重复创建Session
如果需要让API请求也参与Session初始化,可在中间件中先检查Session是否已存在,防止并行请求创建多个Session:
// 在写入Session前先检查是否已有该键 if (!context.Session.Keys.Contains("VisitorGUID")) { // 原有的Cookie检查和Session写入逻辑 Guid parsedGuid; if (!context.Request.Cookies.TryGetValue("CustomClosetsVisitorGUID", out var visitorGuid) || string.IsNullOrWhiteSpace(visitorGuid) || !Guid.TryParse(visitorGuid, out parsedGuid)) { visitorGuid = Guid.NewGuid().ToString(); } context.Response.Cookies.Append("CustomClosetsVisitorGUID", visitorGuid, new CookieOptions { Expires = DateTimeOffset.Now.AddDays(30) }); context.Session.SetString("VisitorGUID", visitorGuid); }
3. 强化Session配置稳定性
在Program.cs中配置Session时,设置明确的超时时间和安全属性:
builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromHours(2); // 延长空闲超时时间 options.Cookie.HttpOnly = true; // 防止前端篡改Session Cookie options.Cookie.IsEssential = true; // 确保Cookie被保存,不受用户非必要Cookie设置影响 });
4. 避免过早触发Session加载
非必要情况下,不要在中间件中提前调用Session.SetString等操作,避免在静态文件、API等无关请求中触发Session创建,减少不必要的Session资源消耗。
内容的提问来源于stack exchange,提问作者Alexandr Zavalny
相关产品推荐
相关产品推荐

