ASP.NET Core Web API缺失Access-Control-Allow-Origin头的CORS问题
问题描述
使用React + Vite前端从ASP.NET Core Web API后端获取数据时,后端返回状态码200,但前端提示缺失Access-Control-Allow-Origin头,跨域请求被阻止。已尝试调整UseCors的调用顺序、查阅相关资料,但问题仍未解决。
后端Startup代码
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Newtonsoft.Json.Serialization; namespace Bakis { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddCors(options => { options.AddPolicy("AllowOrigin", builder => { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials(); }); }); services.AddControllersWithViews().AddNewtonsoftJson(builder => builder.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore).AddNewtonsoftJson(builder => builder.SerializerSettings.ContractResolver = new DefaultContractResolver()); // Other service configurations services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); // Allow CORS app.UseCors("AllowOrigin"); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } }
前端TicketList组件代码
import { useEffect, useState } from "react" import { Ticket } from "../types/ticket" import config from "../types/config"; const TicketList = () => { const [tickets, setTickets] = useState<Ticket[]>([]); useEffect(() => { fetchTickets(); }, []); // Fetch tickets on component mount const fetchTickets = async () => { try { const rsp = await fetch(`${config.baseApiUrl}/tickets`, {mode: 'cors'}); const ticketsData = await rsp.json(); setTickets(ticketsData); } catch (error) { console.error("Error fetching tickets:", error); } }; return ( <div> <div className="row mb-7"> <h5 className="themeFontColor text-center"> All tickets </h5> </div> <table className="table table-striped"> <thead> <tr> <th>Name</th> {/* <th>Description</th> */} {/* <th>Category</th> */} </tr> </thead> <tbody> {tickets.map((t) => ( <tr key={t.ticketId}> <td>{t.TicketName}</td> {/* <td>{t.Description}</td> */} {/* <td>{t.TicketCategory}</td> */} </tr> ))} </tbody> </table> </div> ); } export default TicketList;
报错信息
Cross-Origin Request Blocked: Same-Origin privacy policy prohibits reading the remote resource from https://localhost:4000/api/tickets (cause: Access-Control-Allow-Origin header missing from CORS request). Status code: 200.
解决方案
1. 修复后端服务注册冲突
你的ConfigureServices中同时调用了AddControllersWithViews()和AddControllers(),这会导致CORS策略无法正确绑定到API控制器。移除重复的services.AddControllers();,保留AddControllersWithViews()即可(它已包含API控制器的支持):
public void ConfigureServices(IServiceCollection services) { services.AddCors(options => { options.AddPolicy("AllowOrigin", builder => { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials(); }); }); // 保留这一行,移除services.AddControllers(); services.AddControllersWithViews() .AddNewtonsoftJson(builder => builder.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore) .AddNewtonsoftJson(builder => builder.SerializerSettings.ContractResolver = new DefaultContractResolver()); // Other service configurations }
2. 优化CORS策略(可选)
AllowAnyOrigin与AllowCredentials组合在部分浏览器中可能存在兼容性问题,若前端地址固定(比如Vite默认的http://localhost:5173),建议明确指定允许的Origin:
builder.WithOrigins("http://localhost:5173") // 替换为你的前端实际地址 .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials();
3. 验证HTTPS一致性
确认前端config.baseApiUrl的协议(HTTP/HTTPS)与后端运行地址完全一致,避免HTTPS重定向导致CORS头丢失。
4. 检查响应头
用Postman或curl请求API,查看响应头是否包含Access-Control-Allow-Origin,以此验证CORS策略是否生效。
内容的提问来源于stack exchange,提问作者Thuthutka

