Angular 来自来源的 WebApi Cors 请求已被 CORS 策略阻止

Angular and WebApi Cors Request from origin has been blocked by CORS policy

我有一个 angular 申请 (angular 版本 Angular命令行界面:8.3.26 节点:10.13.0 OS: win32 x64 Angular: 8.2.14)

在 environment.ts 我有 link 和我的后端

    export const environment = {
      baseUrlNG: 'http://localhost:4200/',
      baseUrlApi: 'http://localhost:8082/backend/api/'
    }

后端是一个 C# WebApi 应用程序。 我使用此配置使用 Visual Studio 调试它。

我安装了 nuget Microsoft.AspNet.WebApi.Cors 并且在文件 WebApiConfig.cs 中我有这个代码:

    public static class WebApiConfig
    {
        [EnableCors(origins: "*", headers: "*", methods: "*")]
        public static void Register(HttpConfiguration config)
        {
            config.EnableCors();

            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{language}/{method}/{id}",
                defaults: new { method = RouteParameter.Optional, id = RouteParameter.Optional }

            );
        }
    }

并且在我所有的后端方法中我都有这个装饰器

    [EnableCors(origins: "*", headers: "*", methods: "*")]
    public class AuthenticationController : ApiController
    {
        [Route("api/Authentication/{language}/GuestUser")]
        [HttpPost]
        [Attributes.SiteParameter_Check]
        public IHttpActionResult GuestAuthorization(string language)
        {
            //code with breakpoints never raised.
        }

在 angular 项目中我有这个 post

    function guest(){
      url =  `${environment.baseUrlApi}Authentication/IT/GuestUser`;
      return this.http.post(url, {}, )
        .toPromise()        
        .then(response => {
              //other code        
        })
    }

我遇到了这个错误

Access to XMLHttpRequest at 'http://localhost:8082/backend/api/Authentication/IT/GuestUser' 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.

已经尝试将文件 proxy.conf.json 放入 angular 项目的 src 文件夹中

{
    {
        "/api/*": {
        "target": "http://localhost:8082/backend/api",
        "secure": false,
        "logLevel": "debug"
    }
}

然后我将这一行放入文件 angular.json

     "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "frontend:build",
            "proxyConfig": "src/proxy.conf.json"
      },

这是我的网络配置

    <?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=301879
  -->
<configuration>
    <configSections>

        <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </configSections>

    <system.web>
        <compilation debug="true" targetFramework="4.6.1" />
        <httpRuntime targetFramework="4.6.1" executionTimeout="1200" maxRequestLength="1048576" useFullyQualifiedRedirectUrl="false" minFreeThreads="8" minLocalRequestFreeThreads="4" appRequestQueueLimit="100" />
    </system.web>
    
    <system.webServer>
       <httpProtocol>
         <customHeaders>
           <add name="Access-Control-Allow-Origin" value="*" />
           <add name="Access-Control-Allow-Headers" value="Content-Type" />
           <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
         </customHeaders>
       </httpProtocol>
       
        <validation validateIntegratedModeConfiguration="false" />
        <directoryBrowse enabled="true" />
        
        <handlers>
            <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
            <remove name="OPTIONSVerbHandler" />
            <remove name="TRACEVerbHandler" />
            <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
        </handlers>
    </system.webServer>

    <system.web.extensions>
        <scripting>
            <webServices>
                <jsonSerialization maxJsonLength="2147483647" />
            </webServices>
        </scripting>
    </system.web.extensions>
    
    <connectionStrings>
        ---all my connection strings
    </connectionStrings>
    <entityFramework>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
        <providers>
            <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
        </providers>
    </entityFramework>
    
</configuration>

我错过了什么?

非常感谢

Put this in WebApiConfig

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            var cors = new EnableCorsAttribute("*", "*", "*");// origins, headers, methods  
            config.EnableCors(cors);

            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

请添加这些引用

使用Newtonsoft.Json.Serialization;

使用System.Web.Http.Cors;

注意:WebApiConfig 的变化仅够。无需任何配置

我们曾经在web.config.

有过这样的事情
<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

如果我没记错的话,您需要进行以下设置以允许 ASP.NET 应用程序接收和处理 OPTION。

<system.webServer>
  <handlers>
    <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    <remove name="OPTIONSVerbHandler" />
    <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  </handlers>
</system.webServer>

所有详细信息都在本文中。 https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api

您确定该端口是服务器侦听的端口吗?

不久前我有一个类似的场景(但是 java 和 Jboss),其中 api-url 的端口和监听端口是不同的。

就我而言:

  • Api-url的端口:8080
  • 监听端口:9990

所以我不得不这样设置代理:

{ "/api/*": { "target": "http://localhost:9990", "secure": false, "logLevel": "debug" } }

I also recently experienced same kind of issues while doing the same. I'm copying my MVC API codes here to help you to resolve the same. Kindly configure the same accordingly so that issue will be resolved.

WebApiConfig.cs file

 public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.EnableCors();
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }

web.config file (specific node webServer tag showed below)

<system.webServer>
    <modules>
      <remove name="FormsAuthenticationModule" />
    </modules>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
        <add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
        <add name="Access-Control-Allow-Credentials" value="true" />
      </customHeaders>
    </httpProtocol>
    <handlers>
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
      <!--<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />-->
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>

Add Global.asax file below method (This call specifically for PUT,POST related OPTIONS call.

 protected void Application_BeginRequest(object sender, EventArgs e)
        {
            if (HttpContext.Current.Request.Headers.AllKeys.Contains("Origin") && HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
               //   Response.AddHeader("Access-Control-Allow-Origin", "*");
               // Response.AppendHeader("Access-Control-Allow-Methods", "*");
               // Response.AddHeader("Access-Control-Max-Age", "8000");
                Response.Flush();
            }
        }

If want to restrict in controller level add below decorator in your API controller.

 [EnableCors(origins: "http://locathost:4200", headers: "*", methods: "*")]
    public class AssetsController : ApiController

这是 ASP.NET Core 6 的更新。以前版本的解决方案不适合,因为 web.config、startup.cs 和 WebApiConfig 默认不包含在 ASP.NET 核心 6 项目。

文档中有一个新页面解释了如何设置 CORS。 Enable Cross-Origin Requests (CORS) in ASP.NET Core。我刚刚使用了“CORS with named policy and middleware”的方法,它奏效了!这是对我有用的文档中的代码示例:

var  MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      builder =>
                      {
                          builder.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

// services.AddResponseCaching();

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

附带说明一下, 中的解决方案是通过将“htts://”添加到原点来实现的。这是使用 Sheno-Navy 方法的相同代码示例: var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors();

// services.AddResponseCaching();

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(x => x.AllowAnyHeader().AllowAnyMethod().AllowCredentials().WithOrigins("https://localhost:4200"));

app.UseAuthorization();

app.MapControllers();

app.Run();