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
相关产品推荐
相关产品推荐

