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

ASP.NET Core 8.0 Web API CORS预检请求未返回200响应问题

问题:ASP.NET Core 8.0 Web API跨域请求CORS错误

我开发了ASP.NET Core 8.0 Web API,在Google脚本和本地网页(记事本编写)中调用正常,但从外部站点https://t4.something.edu调用时触发CORS错误:

从源'https://t4.something.edu'访问'https://a.someting.edu/Newsletter/api/newsletter'被CORS策略阻止:预检请求的响应未通过访问控制检查:无HTTP成功状态。

我尝试设置mode: no-cors后,又出现415不支持的媒体类型错误,请问如何让Web API在CORS预检请求中返回200响应解决问题?


相关代码

Program.cs

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy =>
                      {
                          policy.WithOrigins("https://t4.something.edu")
                                .AllowAnyHeader()
                                .AllowAnyMethod();
                      });
});

builder.Services.AddControllers();

// context 
IConfiguration config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .AddEnvironmentVariables()
    .AddCommandLine(args)
    .AddUserSecrets<Program>(true)
    .Build();

builder.Services.AddDbContext<NewsletterContext>(option =>
{
    option.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddTransient<IApiKeyValidation, ApiKeyValidation>();
builder.Services.AddScoped<ApiKeyAuthFilter>();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

前端HTML JavaScript代码

<script>
        function send() 
        {
            var url = 'https://a.something.edu/News/api/news';
            var headers = {
                    'X-API-Key' : "something1234",
                    'Accept': "application/json",
                    'Content-Type': "application/json;charset=utf-8"
            };
            var data = {
                    "email" : document.getElementById("customerEmail").value
            };
            
            var payload = JSON.stringify(data);
            
            var options = {
                method: "POST",
                headers: headers,
                body: payload
            };
            
            try {
                var response = fetch(url, options);
            }catch(error) {
                alert('Error is : ' + error);
            }
            alert('Response is - ' + response);
        }
</script>

web.config配置

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

控制器代码

[Route("api/[controller]")]
 [ApiController]
 public class NewsletterController(NewsletterContext context) : ControllerBase
 {
     private readonly NewsletterContext _context = context;

     [HttpPost]
     public async Task<ActionResult<NewsletterItem>> PostNewsletterItem(NewsletterItem newsletterItem)
     {
        _context.Newsletter_Emails.Add(newsletterItem);

         try
         {
             await _context.SaveChangesAsync();

         }
         catch (DbUpdateConcurrencyException)
         {
            throw;
         }
         return Ok("The record has been saved correctly");
     }
 }

模型代码

namespace NewsletterEmails.Models
{
   public class NewsletterItem
   {
       [Key]
       public required string Email { get; set; }
    }
}

解决方案

1. 移除web.config中的冲突CORS头

web.config中手动添加的Access-Control-Allow-Origin: *会和ASP.NET Core的CORS中间件产生冲突,直接删除该行配置:

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <!-- 移除下面这一行 -->
            <!-- <add name="Access-Control-Allow-Origin" value="*" /> -->
        </customHeaders>
    </httpProtocol>
</system.webServer>

2. 优化CORS策略配置

在Program.cs的CORS策略中添加预检缓存,减少重复请求,同时如果需要携带认证信息(如Cookie),加上AllowCredentials():

policy.WithOrigins("https://t4.something.edu")
      .AllowAnyHeader()
      .AllowAnyMethod()
      .AllowCredentials()
      .SetPreflightMaxAge(TimeSpan.FromHours(1)); // 缓存预检结果1小时

3. 让API Key过滤器跳过预检请求

预检请求(OPTIONS方法)不会携带X-API-Key头,需要修改ApiKeyAuthFilter,直接放行OPTIONS请求:

public class ApiKeyAuthFilter : IAuthorizationFilter
{
    private readonly IApiKeyValidation _apiKeyValidation;

    public ApiKeyAuthFilter(IApiKeyValidation apiKeyValidation)
    {
        _apiKeyValidation = apiKeyValidation;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        // 跳过OPTIONS预检请求,直接返回200
        if (context.HttpContext.Request.Method == HttpMethod.Options.Method)
        {
            context.Result = new OkResult();
            return;
        }

        // 原有API Key验证逻辑
        if (!context.HttpContext.Request.Headers.TryGetValue("X-API-Key", out var apiKey))
        {
            context.Result = new UnauthorizedResult();
            return;
        }

        if (!_apiKeyValidation.IsValid(apiKey))
        {
            context.Result = new UnauthorizedResult();
            return;
        }
    }
}

4. 修复前端请求的URL和异步处理

前端请求的URL与控制器路由不匹配(控制器路由是api/Newsletter,但前端请求的是News/api/news),同时fetch是异步操作,需要用await处理:

async function send() 
{
    // 修正为控制器实际路由
    var url = 'https://a.something.edu/Newsletter/api/newsletter';
    var headers = {
            'X-API-Key' : "something1234",
            'Accept': "application/json",
            'Content-Type': "application/json;charset=utf-8"
    };
    var data = {
            "email" : document.getElementById("customerEmail").value
    };
    
    var payload = JSON.stringify(data);
    
    var options = {
        method: "POST",
        headers: headers,
        body: payload
    };
    
    try {
        var response = await fetch(url, options);
        if(response.ok) {
            var result = await response.text();
            alert('请求成功:' + result);
        } else {
            alert('请求失败:' + response.statusText);
        }
    }catch(error) {
        alert('Error is : ' + error);
    }
}

5. 确保模型绑定匹配

前端发送的email字段与模型的Email属性大小写不同,可添加JsonPropertyName标注确保绑定正确:

namespace NewsletterEmails.Models
{
   public class NewsletterItem
   {
       [Key]
       [JsonPropertyName("email")]
       public required string Email { get; set; }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 22:42:07