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

.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头部无法正常返回。通过以下步骤解决:

  1. 调整中间件顺序:将UseCors移动到UseAuthentication和UseAuthorization之前,确保CORS头部在认证流程执行前被添加
  2. 让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 13:43:11