.NET 5 Core API与Angular前端POST请求CORS问题求助
解决.NET 5 API POST请求CORS跨域问题
问题概述
已完成Oracle数据库、.NET 5 Core API及Angular前端搭建,API运行正常,Angular的GET请求可正常执行,但POST请求触发CORS错误,确认授权环节无问题。
报错信息
Access to XMLHttpRequest at 'https://localhost:44342/api/User/insertUser' from origin 'http://localhost:4200' 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.
现有代码片段
Angular服务POST请求
insertUser(model: Users_Viewmodel) { console.log(model); return this.http.post<Users_Viewmodel>( `${this.apiUrl}/api/User/insertUser`, model ); }
API端CORS配置(原Startup.cs片段)
// outside of my ConfigureServices method readonly string MyAllowOrigins = "_myAllowOrigins"; // in my ConfigureServices method services.AddCors(options => { options.AddPolicy(name: MyAllowOrigins, policy => { policy.WithOrigins("http://localhost:4200") .AllowAnyHeader() .AllowCredentials() .AllowAnyMethod(); }); }); // In my Configure method app.UseCors(MyAllowOrigins);
API控制器代码
[HttpPost("insertUser")] [Authorize] public IActionResult InsertUser([FromBody] Users_Viewmodel model) { try { UserRepo.InsertUser(model); return Ok(); } catch (Exception ex) { return BadRequest(ex.Message); } }
完整Startup.cs代码
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Authorization; using Microsoft.AspNetCore.Server.IISIntegration; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MyApp.Api.Helpers; using MyApp.Api.MiddleWare; using MyApp.WebSocketHub; namespace MyApp.Api { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } readonly string MyAllowOrigins = "_myAllowOrigins"; // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add session-related configuration at the beginning of the method services.AddDistributedMemoryCache(); // Add this line services.AddSession(options => { options.Cookie.Name = "SessionVars"; options.IdleTimeout = TimeSpan.FromMinutes(30); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); services.AddHttpContextAccessor(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddSingleton<SessionManager>(); services.AddCors(options => { options.AddPolicy(name: MyAllowOrigins, policy => { policy.WithOrigins("http://localhost:4200") .AllowAnyHeader() .AllowCredentials() .AllowAnyMethod(); }); }); services.AddSignalR() .AddJsonProtocol(options => { options.PayloadSerializerOptions.PropertyNamingPolicy = null; }); services.AddAuthentication(IISDefaults.AuthenticationScheme); services.AddMvc(config => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); config.Filters.Add(new AuthorizeFilter(policy)); }); services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNamingPolicy = new AllUppercaseNamingPolicy(); }); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "MyApp.Api", Version = "v1" }); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHttpContextAccessor httpContextAccessor) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyApp.Api v1")); } app.UseCors(MyAllowOrigins); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseSession(); app.UseMiddleware<OpcAuthorizeMiddleware>(); SessionManager.Initialize(httpContextAccessor); app.UseEndpoints(endpoints => { endpoints.MapHub<WebSocketHub.WebSocketHub>("/ws"); endpoints.MapControllers(); }); } } }
排查与解决方案
POST请求属于复杂请求,浏览器会先发OPTIONS预检请求验证跨域权限。当前问题核心是预检请求未得到正确的CORS响应头,原因在于中间件顺序错误或自定义授权中间件拦截了预检请求。
方案1:调整中间件顺序(优先推荐)
在.NET 5中,CORS中间件必须放在UseRouting之后、UseAuthorization及自定义中间件之前,确保所有请求(包括OPTIONS预检)都能先应用CORS策略。修改Configure方法的中间件顺序:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHttpContextAccessor httpContextAccessor) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyApp.Api v1")); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); // 将UseCors移至UseRouting之后,确保路由匹配后应用CORS策略 app.UseCors(MyAllowOrigins); app.UseAuthentication(); app.UseAuthorization(); app.UseSession(); app.UseMiddleware<OpcAuthorizeMiddleware>(); SessionManager.Initialize(httpContextAccessor); app.UseEndpoints(endpoints => { endpoints.MapHub<WebSocketHub.WebSocketHub>("/ws"); endpoints.MapControllers(); }); }
方案2:放行自定义授权中间件中的OPTIONS请求
若无法调整中间件顺序,修改OpcAuthorizeMiddleware,让它直接放行OPTIONS预检请求,不做授权校验:
public class OpcAuthorizeMiddleware { private readonly RequestDelegate _next; public OpcAuthorizeMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { // 直接放行OPTIONS预检请求 if (context.Request.Method.Equals("OPTIONS", StringComparison.OrdinalIgnoreCase)) { context.Response.Headers.Add("Access-Control-Allow-Origin", "http://localhost:4200"); context.Response.Headers.Add("Access-Control-Allow-Headers", "*"); context.Response.Headers.Add("Access-Control-Allow-Methods", "*"); context.Response.StatusCode = StatusCodes.Status200OK; await context.Response.CompleteAsync(); return; } // 执行原有授权逻辑 await _next(context); } }
额外验证点
- 确认Angular请求未携带未被允许的自定义请求头(已配置
AllowAnyHeader(),通常无需额外处理) - 检查API运行地址
https://localhost:44342是否正确,协议、端口与配置一致
内容的提问来源于stack exchange,提问作者Justin de Gois
相关产品推荐
相关产品推荐

