无法在ASP.Net Core Web API中启用CORS

时间:2018-09-06 12:31:27

标签: asp.net reactjs .net-core cors

我用一个控制器创建了一个ASP.Net CORE Web API项目,现在想从客户端(反应)Web应用程序中调用它。

但是,调用失败,并且“所请求的资源上没有'Access-Control-Allow-Origin'标头。”

从Fiddler调用同一端点时,预期的响应头不存在。

多亏了ATerry,我有了进一步的了解:标头不存在,因为React Web应用程序和.Net Core Web API托管在同一个盒子中。 React填充了请求Origin:标头,该标头与(API)框相同,因此服务器(真的很聪明)不会添加Allow -...响应标头。但是,由于缺少这些标头,React应用拒绝了响应。

我正在使用.Net Core v2.1(本文撰写时为最新)。

我基于

构建了代码

https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1

我检查了这些

https://weblog.west-wind.com/posts/2016/Sep/26/ASPNET-Core-and-CORS-Gotchas

CORS in .NET Core

How to enable CORS in ASP.NET Core

...但是所有建议都没有。

有什么想法吗?

这是我配置.Net Core应用程序的方式(代码从实际更改为尝试并允许任何操作):

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)
    {
        // Enable CORS (Cross Origin Requests) so that the React app on a different URL can access it
        // See https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1
        services.AddCors(options =>
        {
            options.AddPolicy(Global.CORS_ALLOW_ALL_POLICY_NAME, builder => builder
                .AllowAnyOrigin()
                .AllowAnyHeader()
                .AllowAnyMethod()
                .AllowCredentials());
        });

        services.AddMvc();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseCors(Global.CORS_ALLOW_ALL_POLICY_NAME);

        app.UseHttpsRedirection();
        app.UseMvc();
    }
}

由于上述原因而失败,我也将CORS属性添加到控制器类和控制器方法:

[Route("api/[controller]")]
[ApiController]
[EnableCors(Global.CORS_ALLOW_ALL_POLICY_NAME)]
public class DealsController : ControllerBase
{
[...]
[HttpGet]
    [EnableCors(Global.CORS_ALLOW_ALL_POLICY_NAME)]
    public ActionResult<List<Deal>> GetAll()
    {
        return Store;
    }
}

我得到的响应头:

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-Powered-By: ASP.NET
Date: Thu, 06 Sep 2018 12:23:27 GMT

缺少的标题是:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:3000

4 个答案:

答案 0 :(得分:2)

我相信它也可以与LOCALHOST托管一起正常工作,只需执行以下更改并删除以及任何其他更改/配置即可。

替换此:

        // Enable CORS (Cross Origin Requests) so that the React app on a different URL can access it
    // See https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1
    services.AddCors(options =>
    {
        options.AddPolicy(Global.CORS_ALLOW_ALL_POLICY_NAME, builder => builder
            .AllowAnyOrigin()
            .AllowAnyHeader()
            .AllowAnyMethod()
            .AllowCredentials());
    });

与此:

services.AddCors();

并替换为:

app.UseCors(Global.CORS_ALLOW_ALL_POLICY_NAME);

与此:

app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());

注意:

  • 即使在LOCALHOST上配置了Web Api和React应用也不意味着它们来自同一来源,这是因为它们托管在不同的端口上,例如react app托管在LOCALHOST:3000上,而Web Api是托管在LOCALHOST:5000。如果客户端(反应应用)从其他端口请求,Web api将会投诉。

  • 上面的Web Api代码将允许任何ORIGIN,并且在生产应用程序中这是不安全的,因此您需要允许特定的ORIGIN访问CORS。

答案 1 :(得分:1)

您可以尝试以下类似方法,如此处所述:https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.2

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddPolicy("AllowSpecificOrigin",
            builder => builder.WithOrigins("http://example.com"));
    });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
    ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    // Shows UseCors with named policy.
    app.UseCors("AllowSpecificOrigin");

    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    });
}

在您的情况下,可以将其更改为类似于下面的代码。

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(Global.CORS_ALLOW_ALL_POLICY_NAME,
                builder =>
                {
                    builder.AllowAnyOrigin()
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials();
                }));

        services.AddMvc();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseCors(Global.CORS_ALLOW_ALL_POLICY_NAME);

        app.UseHttpsRedirection();
        app.UseMvc();
    }
}

此代码看上去可能与您的代码没有什么不同,但是,定义动作(您称为构建器)的方式略有不同。希望对您有帮助,祝您好运! :)

答案 2 :(得分:0)

设法通过将用于访问服务器的URL从基于localhost的URL更改为基于IP地址的URL(从localhost / api更改为192.168.1.96/api)来解决该问题。

似乎ATerry提到的部分过滤是基于主机名的:如果主机名是localhost,则IIS不会发送Allow -...标头。问题在于React需要它们。

答案 3 :(得分:0)

我最近也遇到了同样的问题,但是怀疑我的问题是否与CORS有关。因此,我去了将应用程序部署到本地IIS,以检查是否可以解决该问题。然后检查日志,发现与数据模型中的循环引用有关的问题-“检测到属性的自我引用循环。”。在Startup.js中应用了一个操作来解决该问题,

    services.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
                .AddJsonOptions(options =>
                {
                    options.SerializerSettings.Formatting = Formatting.Indented;

                    // this line
                    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                });