React调用ASP.NET Core后端Fetch请求时如何解决CORS错误?
问题场景
使用Visual Studio Community开发React前端+ASP.NET后端的全栈项目时,React发起POST请求到后端API时触发CORS错误:
Access to fetch at '.../api/Email/Send' from origin 'https://localhost:44493' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
React请求代码:
const sendEmail = async(event) => { event.preventDefault(); let baseUrl = '...some base url'; let emailAddress = email.email_address; let emailMessage = emailText.message; let emailData = { "Id": "demo", "Amount": 37200, "Sig": "YTdjfyDBFNAKdufyBAiPPeefKLdjnf", "emailAddress": emailAddress, "notes": emailMessage }; await fetch(`${baseUrl}/api/Email/Send`,{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(emailData) }) .then((res)=> res.json()) .then((data) => console.log(data)) .catch((err) => console.log(err)); };
当前ASP.NET的Program.cs代码:
var builder = WebApplication.CreateBuilder(args); var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddTransient<BillEmailService>(); builder.Services.AddTransient<TransactionInfoService>(); builder.Services.AddTransient<PaymentProviderService>(); builder.Services.AddTransient<StoreInfoService>(); builder.Services.AddTransient<DbSetup>(); builder.Services.AddTransient<InlineImageService>(); builder.Services.AddHttpClient<InlineImageService>(); builder.Services.AddTransient<Feedback>(); builder.Services.AddTransient<LoyaltyEngineFactory>(); builder.Services.AddHttpClient("LoyaltyEngineFactory"); builder.Services.AddTransient<MasterpassClientFactory>(); builder.Services.AddHttpClient("MasterpassClient"); builder.Services.AddTransient<TransactionInfoFactory>(); builder.Services.AddHttpClient("TransactionInfoClient"); builder.Services.AddSingleton<IDbConnectionFactory>(s => new DbConnectionFactory(connectionString)); builder.Services.AddTransient<IDbAdapter, DbAdapter>(); builder.Services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApp", Version = "v1" }); }); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApp v1")); app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseDefaultFiles(); app.UseStaticFiles(); app.MapControllerRoute("default", "{controller=Demo}/{action=Get}/{id?}"); app.MapFallbackToFile("index.html"); using var scope = app.Services.CreateScope(); var repo = scope.ServiceProvider.GetService<DbSetup>(); await repo!.RunScripts(); app.Run();
解决方案
要解决这个CORS错误,需要在ASP.NET后端中正确配置并启用CORS中间件,步骤如下:
1. 注册CORS服务
在builder.Services.AddControllers()之后,添加CORS服务配置,指定允许访问的前端源(这里是你的React地址https://localhost:44493),以及允许的HTTP方法、请求头:
builder.Services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null); // 新增:注册CORS服务 builder.Services.AddCors(options => { options.AddPolicy("AllowReactOrigin", policy => { // 允许指定的React前端域名 policy.WithOrigins("https://localhost:44493") .AllowAnyHeader() // 允许所有请求头 .AllowAnyMethod(); // 允许所有HTTP方法(GET/POST等) // 如果你的请求需要携带Cookie或认证信息,还要加上 .AllowCredentials() }); });
2. 启用CORS中间件
在中间件管道中,必须将UseCors放在UseRouting之后、UseAuthorization之前,否则CORS配置不会生效:
app.UseHttpsRedirection(); app.UseRouting(); // 新增:启用CORS,使用上面定义的策略 app.UseCors("AllowReactOrigin"); app.UseAuthorization(); app.UseDefaultFiles(); app.UseStaticFiles();
修改后的完整Program.cs(关键部分已标注)
var builder = WebApplication.CreateBuilder(args); var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddTransient<BillEmailService>(); builder.Services.AddTransient<TransactionInfoService>(); builder.Services.AddTransient<PaymentProviderService>(); builder.Services.AddTransient<StoreInfoService>(); builder.Services.AddTransient<DbSetup>(); builder.Services.AddTransient<InlineImageService>(); builder.Services.AddHttpClient<InlineImageService>(); builder.Services.AddTransient<Feedback>(); builder.Services.AddTransient<LoyaltyEngineFactory>(); builder.Services.AddHttpClient("LoyaltyEngineFactory"); builder.Services.AddTransient<MasterpassClientFactory>(); builder.Services.AddHttpClient("MasterpassClient"); builder.Services.AddTransient<TransactionInfoFactory>(); builder.Services.AddHttpClient("TransactionInfoClient"); builder.Services.AddSingleton<IDbConnectionFactory>(s => new DbConnectionFactory(connectionString)); builder.Services.AddTransient<IDbAdapter, DbAdapter>(); builder.Services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null); // --- 新增:注册CORS服务 --- builder.Services.AddCors(options => { options.AddPolicy("AllowReactOrigin", policy => { policy.WithOrigins("https://localhost:44493") .AllowAnyHeader() .AllowAnyMethod(); // 若需携带凭证,取消注释下面一行 // .AllowCredentials(); }); }); // --- 新增结束 --- builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApp", Version = "v1" }); }); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApp v1")); app.UseHttpsRedirection(); app.UseRouting(); // --- 新增:启用CORS中间件 --- app.UseCors("AllowReactOrigin"); // --- 新增结束 --- app.UseAuthorization(); app.UseDefaultFiles(); app.UseStaticFiles(); app.MapControllerRoute("default", "{controller=Demo}/{action=Get}/{id?}"); app.MapFallbackToFile("index.html"); using var scope = app.Services.CreateScope(); var repo = scope.ServiceProvider.GetService<DbSetup>(); await repo!.RunScripts(); app.Run();
额外注意事项
- 开发环境中如果需要临时允许所有源,可以用
.AllowAnyOrigin()代替.WithOrigins(...),但生产环境必须指定具体的允许域名,避免安全风险。 - 如果你的请求包含自定义头或需要携带认证凭证(比如Cookie),要确保CORS策略中配置了对应的允许项(
.AllowCredentials()、.WithHeaders(...))。 - 确认React中的
baseUrl是后端的正确地址,且端口、协议(HTTP/HTTPS)与CORS配置一致。
内容的提问来源于stack exchange,提问作者George Marwanqana

