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

ASP.NET Core Web API缺失Access-Control-Allow-Origin头的CORS问题

ASP.NET Core Web API + React/Vite 跨域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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 21:47:09