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

.NET Core 6中Ajax调用控制器时Cookie操作失效求助

问题

我有一个基于.NET Core 6、使用Razor页面的Web应用,目前正在将前端迁移为JavaScript UI,并新增控制器处理Ajax请求。控制器通过依赖注入(DI)调用负责业务逻辑的manager类。

现有Web页面中,调用manager类通过DI注入的IHttpContextAccessor.HttpContext.Response.Cookies读写Cookie一直正常,能看到6个Cookie。但通过Ajax调用控制器中的同一manager代码时,Cookie集合为空;即使添加测试代码_httpContextAccessor.HttpContext.Response.Cookies.Append("Test", "TestValue");,执行后也看不到Cookie,且无任何报错。

我在Startup.cs中配置了DI:

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

也尝试过添加:

services.AddHttpContextAccessor();

还测试了多种CookieOptions,但都无效。


补充代码

Manager类代码

public class AppManager : IAppManager
{
  private readonly IHttpContextAccessor _httpContextAccessor;

  public AppManager(IHttpContextAccessor httpContextAccessor )
  {
    _httpContextAccessor = httpContextAccessor;
  }

  public string ReadCookie(string key)
  {  
    // 添加了下面这行,但毫无作用
    // Cookie初始数量为0,执行Append后还是0
    _httpContextAccessor.HttpContext.Response.Cookies.Append("Test", "TestValue");

    var data = _httpContextAccessor.HttpContext.Request.Cookies[key];

    return data;
  }

  public void WriteCookie(string key, string value, int? daysToPersist = null)
  {
    // 这里试过多种配置选项
    var options = new CookieOptions 
    { 
        SameSite    = SameSiteMode.None,
        Secure      = true,
        IsEssential = true,
        HttpOnly    = false
    };

    if (daysToPersist > 0)
        options.Expires = DateTime.Now.AddDays((double)daysToPersist);
    else
        options.Expires = DateTime.Now.AddSeconds((double)60);

    _httpContextAccessor.HttpContext.Response.Cookies.Append(key, value, options);

  }

  public void DeleteCookie(string key)
  {
    _httpContextAccessor.HttpContext.Response.Cookies.Delete(key);
  }

}

控制器代码

public Guid GetUserGuidFromCookie()
{
    string userGuidString = ReadCookie(UserGuidKey);
    if (!Guid.TryParse(userGuidString, out Guid userGuid))
    {
        userGuid = Guid.NewGuid();
        WriteCookie(UserGuidKey, userGuid.ToString(), 14);
    }
    return userGuid;
}

Program.cs代码

public class Program
{
   public static void Main(string[] args)
   {
       CreateHostBuilder(args).Build().Run();
   }

   public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
}

Startup.cs代码

public class Startup
{
 public Startup(IConfiguration configuration)
 {
    Configuration = configuration;
 }

 public IConfiguration Configuration { get; }

 public void ConfigureServices(IServiceCollection services)
 {
    services.AddControllers()
            .AddJsonOptions(options =>
                {
                      options.JsonSerializerOptions.PropertyNamingPolicy = null;
                }
            );

    services.AddRazorPages()  //.AddRazorRuntimeCompilation()
            .AddRazorOptions(options =>
            {
                options.PageViewLocationFormats.Add("/Pages/DisplayTemplates/{0}.cshtml");
            });


    services.AddSingleton<IAppSettings>(Configuration.GetSection("App").Get<AppSettings>());
    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();         
    
    services.AddScoped<IAppManager, AppManager>();


    services.AddCors(o => o.AddPolicy("ApiPolicy", builder =>
    {
        builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader();
    }));

    services.AddHttpContextAccessor();

 }

 public void Configure( IApplicationBuilder app, IWebHostEnvironment env,
                        IDataRepo dataRepo)
 {
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");  
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles();

    app.UseRouting();

    app.UseCors();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapRazorPages();
    });
  }
 }

原因分析与解决办法

1. CORS配置存在安全限制问题

你的CORS策略使用AllowAnyOrigin(),但浏览器不允许通配符*与携带凭证(Cookie)的请求共存,直接导致请求无法携带现有Cookie,同时服务器设置的新Cookie也不会被浏览器保存。

  • 修复方式:替换为具体前端域名,同时添加允许凭证的配置:
    services.AddCors(o => o.AddPolicy("ApiPolicy", builder =>
    {
        builder.WithOrigins("https://your-frontend-domain.com") // 替换为实际前端域名
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials();
    }));
    
  • 同时在Configure方法中指定使用该策略:app.UseCors("ApiPolicy");,而非无参数的app.UseCors();

2. Ajax请求未显式携带凭证

前端发送Ajax请求时,必须主动声明携带凭证,否则浏览器不会自动带上Cookie:

  • Fetch API示例:
    fetch('/api/your-controller-action', {
        method: 'GET',
        credentials: 'include'
    });
    
  • jQuery示例:
    $.ajax({
        url: '/api/your-controller-action',
        type: 'GET',
        xhrFields: {
            withCredentials: true
        }
    });
    

3. Cookie配置与环境不匹配

  • 你设置了SameSiteMode.None,这要求必须同时开启Secure = true(仅HTTPS环境有效),如果是本地HTTP开发环境,该配置会导致Cookie无法被浏览器保存。建议根据环境动态调整:
    var options = new CookieOptions 
    { 
        SameSite    = env.IsDevelopment() ? SameSiteMode.Lax : SameSiteMode.None,
        Secure      = !env.IsDevelopment(),
        IsEssential = true,
        HttpOnly    = false
    };
    
  • 避免使用DateTime.Now(依赖本地时区),改用DateTimeOffset.UtcNow防止过期时间异常:
    options.Expires = DateTimeOffset.UtcNow.AddDays((double)daysToPersist).DateTime;
    

4. HttpContextAccessor重复注册

Startup.cs中同时注册了services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>()和services.AddHttpContextAccessor(),后者已经内部完成了单例注册,重复注册可能引发潜在问题,建议只保留services.AddHttpContextAccessor();。


内容的提问来源于stack exchange,提问作者WillC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 09:07:02