在启动中启用 CORS 失败并出现预检错误

Posted

技术标签:

【中文标题】在启动中启用 CORS 失败并出现预检错误【英文标题】:Enabling CORS in Startup fails with preflight error 【发布时间】:2019-02-18 14:13:43 【问题描述】:

我正在尝试在 Startup.cs 中启用 CORS,但没有成功。我在端口 4200 上有一个 Angular 应用程序,试图与我的 c# Web 应用程序通信。我在 Angular 中不断收到此错误

无法加载 http://localhost:52008/Account/GetJWT:预检响应没有 HTTP ok 状态。

我的研究似乎表明 CORS 未正确启用。知道我错过了什么吗?

public void ConfigureServices(IServiceCollection services)

.....
    services.AddCors(options =>
    
        options.AddPolicy("EnableCORS", builder =>
        
            builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials()
            .Build();
        );
    );
    .........


public void Configure(IApplicationBuilder app, IHostingEnvironment env)

.......
 app.UseCors("EnableCORS");
 ........
 

这是 Angular POST 请求:

  login(form: NgForm) 
    let credentials = JSON.stringify(form.value);
    console.log(credentials);
    this.http.post("http://localhost:52008/Account/GetJWT", credentials, 
      headers: new HttpHeaders(
        "Content-Type": "application/json"
      )
    )
  

POSTMAN 查询结果

【问题讨论】:

似乎AllowCredentials 导致OPTIONS 动词see this QA 出现问题。将[EnableCors("EnableCORS")] 放入控制器似乎比为每个请求全局注册更好。如果您可以使用邮递员查看标题,那将是最好的.. 或者app.UseCors("EnableCORS");app.UseMvc()之后被调用.. 请查看Fiddler Proxy,熟悉它并经常使用它 - 它会准确地告诉您所有您的请求和响应的情况,以及作为 API/全栈开发人员,您将节省数小时来处理此类问题。找出预检请求的 HTTP 状态是什么,您将能够更好地确定如何修复它。 Windows 身份验证?改用 IIS CORS 模块,docs.microsoft.com/en-us/iis/extensions/cors-module/… @BagusTesa 上面的图片是您在 Postman 中看到标题的意思吗?我检查了-app.UseCors("EnableCORS"); 在 app.UseMvc() 之前被调用 【参考方案1】:

使用以下代码启用 CORS。 .NET Core 版本:2.1 和 Angular 版本:1.6.7

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.AddMvc()
            .AddJsonOptions(options =>
        
            options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.None;                
        );

        services.AddCors();
    

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
     
        app.UseCors(options =>
        
            options.AllowAnyMethod();
            options.AllowAnyOrigin();
            options.AllowAnyHeader();
        );

        app.UseMvc();
       

角度代码:

$http.post("http://localhost:52008/Account/GetJWT", credentials,
    headers: new HttpHeaders(
        "Content-Type": "application/json"
)).then(
function(response) 
    console.log(response);
,
function() 
    console.log("unable to login");
);

如果问题仍然存在,请告诉我。

【讨论】:

【参考方案2】:
     public void ConfigureServices(IServiceCollection services)
        
           //add cors service
            services.AddCors(options => options.AddPolicy("Cors",
                builder => 
                    builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
                 ));

            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();
        
        app.UseCors("Cors");//------>let app use new service
        app.UseMvc();

    

在你的控制器内部,确保你从身体上抓取物体

//发布请求

 [HttpPost]
    public Message Post([FromBody] Message message)
    

    var msg = new Message  Owner = message.Owner, Text = message.Text ;
    db.Messages.AddAsync(msg);
    db.SaveChangesAsync();

    return message;


【讨论】:

【参考方案3】:

您可以像下面这样在 startup.cs 中配置核心并将源添加到 ConfigurationServices 中,如下所示。

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!");
    );

将 CORS 策略添加到特定操作。

[HttpGet]
[EnableCors("AllowSpecificOrigin")]
public IEnumerable<string> Get()

    return new string[]  "value1", "value2" ;

参考:Enable Cross-Origin Requests (CORS) in ASP.NET Core

【讨论】:

【参考方案4】:

更改为您的 web.config:

<system.webServer>

    ...

<httpProtocol>
    <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept, Cache-Control" />
        <add name="Access-Control-Allow-Credentials" value="true" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    </customHeaders>
</httpProtocol>
</system.webServer>

【讨论】:

以上是关于在启动中启用 CORS 失败并出现预检错误的主要内容,如果未能解决你的问题,请参考以下文章

CORS 选项预检悬挂

Yii 和 Vue2 CORS 启用。服务器以 404 错误响应预检 OPTIONS 请求

即使没有发出预检请求,也会在 POST 请求中出现 CORS 错误

Rails 在 CORS 预检选项请求中以 404 响应

预检失败时如何通过属性而不是通过 Application_BeginRequest 启用 CORS

VB.NET Web API CORS PUT 预检 405 错误