.NET 8 WebAPI跨域CORS异常:非GET请求遭拦截求助
.NET 8 WebAPI 部署后 CORS 问题排查与解决
问题现象
- 同一服务器部署Vue/Vuetify站点和.NET 8 WebAPI,开发环境一切正常,测试服务器上GET请求正常,但POST/PATCH等非GET请求全部因CORS策略拦截失败
- Chrome控制台报错:
从源'https://crmappdev1:8051'访问XMLHttpRequest at 'https://crmappdev1:8050/api/generic/getAnyServiceCarisma'已被CORS策略阻止:对预检请求的响应未通过访问控制检查:请求的资源上不存在'Access-Control-Allow-Origin'头部。
- Chrome网络标签显示:POST请求返回"Unauthorized",且触发了OPTIONS预检请求
已尝试的排查操作
- 宽松CORS配置:在Program.cs中配置允许指定源、所有请求头部、指定HTTP方法(GET/PUT/POST/DELETE/OPTIONS/PATCH)及凭证携带,开发环境正常,但测试服务器无效
- 硬编码CORS响应头:自定义中间件手动设置CORS相关头部,开发环境正常,但测试服务器上OPTIONS/POST请求仍未返回
Access-Control-Allow-Origin头部 - 排除外部防火墙影响:远程桌面连接到测试服务器,本地访问Web应用,问题依旧,排除外部防火墙拦截可能
硬编码CORS头部的中间件代码
app.Use(async (ctx, next) => { var org = ctx.Request.Headers["Origin"]; if (!string.IsNullOrWhiteSpace(org) && allowedOrigins.Contains(org)) { ctx.Response.Headers.Append("Access-Control-Allow-Origin", org); } ctx.Response.Headers.Append("Access-Control-Allow-Credentials", "true"); if (HttpMethods.IsOptions(ctx.Request.Method)) { ctx.Response.Headers.Append("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS, PATCH"); ctx.Response.Headers.Append("Access-Control-Allow-Headers", "content-type"); await ctx.Response.CompleteAsync(); return; } await next(); });
当前Program.cs核心配置代码
public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); List<string> allowedOrigins = new List<string> { "http://localhost:8080", "http://localhost:8051", // 测试环境地址 "http://crmappdev1:8051", "https://crmappdev1:8051" }; builder.Services.AddCors( options => { options.AddDefaultPolicy( policy => { policy.WithOrigins(allowedOrigins.ToArray()) //.AllowAnyMethod() //.WithMethods("GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH") //.AllowAnyHeader() //.AllowCredentials() ; } ); }); // 其他服务注册 builder.Configuration .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate(); builder.Services.AddAuthorization(options => { options.FallbackPolicy = options.DefaultPolicy; }); builder.Services.AddMvc(option => option.EnableEndpointRouting = false).AddNewtonsoftJson(); var app = builder.Build(); app.UseSwagger(); app.UseSwaggerUI(); app.UseCors( builder => { builder .WithOrigins(allowedOrigins.ToArray()) .AllowAnyHeader() .AllowCredentials() .WithMethods("GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH") //.AllowAnyMethod() ; }); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run(); }
解决方法(已解决)
问题根源是OPTIONS预检请求被Negotiate认证拦截,导致CORS头部无法正常返回。通过以下步骤解决:
- 调整中间件顺序:将
UseCors移动到UseAuthentication和UseAuthorization之前,确保CORS头部在认证流程执行前被添加 - 让OPTIONS请求绕过认证:添加中间件专门处理OPTIONS预检请求,直接返回200状态码并完成响应,避免触发认证逻辑
修改后的Program.cs关键部分代码:
var app = builder.Build(); app.UseSwagger(); app.UseSwaggerUI(); // 优先处理CORS配置 app.UseCors(builder => { builder.WithOrigins(allowedOrigins.ToArray()) .AllowAnyHeader() .AllowCredentials() .WithMethods("GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"); }); app.UseHttpsRedirection(); app.UseAuthentication(); // 拦截OPTIONS预检请求,直接返回200,绕过认证 app.Use(async (context, next) => { if (context.Request.Method == HttpMethod.Options.Method) { context.Response.StatusCode = StatusCodes.Status200OK; await context.Response.CompleteAsync(); return; } await next(); }); app.UseAuthorization(); app.MapControllers(); app.Run();
完成以上调整后,OPTIONS请求不会触发认证流程,CORS头部能正常返回,POST/PATCH等非GET请求即可通过CORS检查。
内容的提问来源于stack exchange,提问作者Toby Fieldgroove
相关产品推荐
相关产品推荐

