【问题标题】:EnableCors attribute not adding Access-Control-Allow-Origin to API responsesEnableCors 属性未将 Access-Control-Allow-Origin 添加到 API 响应
【发布时间】:2020-11-20 14:11:25
【问题描述】:

问题:

由于某种原因,启用 CORS 时,Access-Control-Allow-Origin 标头未包含在响应中。

错误:

从 'https://.../api/endpoints/some-path' 访问 XMLHttpRequest 来源“https://some.site.com”已被 CORS 政策阻止: 对预检请求的响应未通过访问控制检查:否 'Access-Control-Allow-Origin' 标头出现在请求的 资源。

配置 (.NET MVC 5)

web.config 标头:

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Credentials" value="true"/>
      <add name="Access-Control-Allow-Headers" value="Content-Type" />
      <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, OPTIONS" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Web API 配置:

config.EnableCors();

API 端点:

[RoutePrefix("api/endpoints")]
[EnableCors(origins: "https://some.site.com", headers: "*", methods: "*")]
public class MyApiController : ApiController
{
    [HttpPost]
    [Route("some-path")]
    [EnableCors(origins: "https://some.site.com", headers: "*", methods: "*")]
    public ResponseModel GetSomeResponse(DataModel model) { ... }
}

global.asax.cs

protected void Application_BeginRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        HttpContext.Current.Response.Flush();
}

我可以成功让应用程序返回该标头的唯一方法是将其作为自定义标头明确包含在 web.config 中:

<add name="Access-Control-Allow-Origin" value="https://some.site.com" />

【问题讨论】:

标签: c# asp.net-mvc api


【解决方案1】:

使用HttpOptions 标头和相同的路由名称添加相同的方法。浏览器会将预检请求发送到您的控制器。这意味着将触发Options方法访问服务器的头信息。

[HttpOptions]
[Route("some-path")]
[EnableCors(origins: "https://some.site.com", headers: "*", methods: "*")]
public ResponseModel GetSomeResponse(DataModel model) { ... }

【讨论】:

    【解决方案2】:

    发件人:https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api

    确认 Access-Control-Request-Method 和 Access-Control-Request-Headers 标头随请求一起发送,并且 OPTIONS 标头通过 IIS 到达应用程序。

    要配置 IIS 以允许 ASP.NET 应用接收和处理 OPTION 请求,请将以下配置添加到应用的 web.config 文件的 部分:

    <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>
    

    删除 OPTIONSVerbHandler 会阻止 IIS 处理 OPTIONS 请求。 ExtensionlessUrlHandler-Integrated-4.0 的替换允许 OPTIONS 请求到达应用,因为默认模块注册只允许带有无扩展 URL 的 GET、HEAD、POST 和 DEBUG 请求。

    【讨论】:

      【解决方案3】:

      这对我有用。处理飞行前请求和cors 网页配置

      <system.webServer>   
          <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>
      

      Global.asax.cs

      protected void Application_BeginRequest(object sender, EventArgs e)
              {
                  if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
                  {
                      //These headers are handling the "pre-flight" OPTIONS call sent by the browser
                      HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
                      HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "*"); // For All HttpVerb
                      //HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
                      //HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept");
                      HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "*");
                      //HttpContext.Current.Response.AddHeader("Access-Control-Allow‌​-Credentials", "true");
                      HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "600");//1728000
                      HttpContext.Current.Response.StatusCode = 204;
      
                      HttpContext.Current.Response.End();
                  }
              }
      

      WebApiConfig.cs

      public static void Register(HttpConfiguration config)
      {
          config.EnableCors();
          ....
      }
      

      在控制器中添加属性

      [EnableCors(origins: "*", headers: "*", methods: "*")]
      

      【讨论】:

        【解决方案4】:

        如果可能,请始终尽量保持您的代码简单清晰

        实际上,无需更改 web.configcontrollersglobal.asax.cs .所以清理它们并只需在 Startup.cs 文件中的 Configure 方法中使用以下配置

        app.UseExceptionHandler(builder =>
        {
            builder.Run(
            async context =>
            {
                context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
        
                var error = context.Features.Get<IExceptionHandlerFeature>();
                if (error != null)
                {
                    context.Response.AddApplicationError(error.Error.Message);
                    await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false);
                }
            });
        });
        

        其中ResponseExtensions 被定义为具有以下详细信息的扩展:

        public static class ResponseExtensions
        {
            public static void AddApplicationError(this HttpResponse response, string message)
            {
                response.Headers.Add("Application-Error", message);
                // CORS
                response.Headers.Add("access-control-expose-headers", "Application-Error");
            }
        }
        

        这在我完全基于 API 的 Asp.net 项目中运行良好。

        【讨论】:

          【解决方案5】:

          为所有控制器全局设置 CORS。在WebApiConfig 类中,创建EnableCorsAttribute 的实例并在EnableCors 方法中使用:

          var cors = new EnableCorsAttribute("https://some.site.com", "*", "*");
          config.EnableCors(cors);
          

          【讨论】:

          • 这可行,但与将其添加到 web.config 中的效果相同。我希望基于每个 API 或端点对 CORS 策略进行更细粒度的控制,而不是将其设置为所有请求的相同值。
          • 如果您想根据 API 实现 CORS,请将此属性应用于方法属性而不是控制器级别:[EnableCors(origins: "https://some.site.com", headers: "*", methods: "*")]
          • 是的,原帖中提到了。添加属性不会导致将Access-Control-Allow-Origin 标头添加到响应中。
          • 但是在原始帖子中,您已将其应用于控制器级别。从控制器中删除并仅应用于方法。
          • 你说得对,我已经对其进行了编辑以表明我已经尝试了这两种方法。感谢您指出这一点。
          【解决方案6】:

          全局启用 CORS 所描述的方法也可用于跨 API 启用 CORS,而无需按照下面的 WebApiConfig 注释每个控制器

          public static void Register(HttpConfiguration config)
          {
              var corsAttr = new EnableCorsAttribute("http://example.com", "*", "*");
              config.EnableCors(corsAttr);
          }
          

          【讨论】:

          • 您好,欢迎来到 StackOverflow。如果您可以提供有关代码的更多详细信息,那将是一个更好的答案,这是一个提示:stackoverflow.com/help/how-to-answer
          • 你是对的,但这并不能解决我的问题。我需要能够为每个端点设置不同的Access-Control-Allow-Origin
          【解决方案7】:

          我遵循了 Shaun 在下面的帖子中分享的相同步骤,我们可以在方法级别启用 CORS。这对我来说可以。 你能在最后尝试一下吗?

          Asp.Net WebApi2 Enable CORS not working with AspNet.WebApi.Cors 5.2.3

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-12-16
            • 2019-05-10
            • 2023-01-13
            • 2016-06-10
            • 1970-01-01
            • 1970-01-01
            • 2014-08-14
            相关资源
            最近更新 更多