.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

