You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.Session Cookie,后到达的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 10:05:17