使 CORS 不能与 AspNet.WebApi.CORS 5.2.3一起工作

我尝试按照 http://enable-cors.org/server_aspnet.html 上的步骤进行操作 让我的 RESTful API (使用 ASP.NET WebAPI2实现)与跨源请求(启用 CORS)一起工作。除非我修改 web.config,否则它不能工作。

我安装了 WebApi Cors 依赖项:

install-package Microsoft.AspNet.WebApi.Cors -ProjectName MyProject.Web.Api

然后在我的 App_Start中,我得到了类 WebApiConfig如下:

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var corsAttr = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(corsAttr);


var constraintsResolver = new DefaultInlineConstraintResolver();


constraintsResolver.ConstraintMap.Add("apiVersionConstraint", typeof(ApiVersionConstraint));
config.MapHttpAttributeRoutes(constraintsResolver);
config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));
//config.EnableSystemDiagnosticsTracing();
config.Services.Replace(typeof(ITraceWriter), new SimpleTraceWriter(WebContainerManager.Get<ILogManager>()));
config.Services.Add(typeof(IExceptionLogger), new SimpleExceptionLogger(WebContainerManager.Get<ILogManager>()));
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
}
}

但是在运行应用程序之后,我用 Fiddler 请求一个资源,比如: Http://localhost:51589/api/v1/persons 在响应中,我看不到我应该看到的 HTTP 头,比如:

  • Access-Control-Allow-Methods: POST, PUT, DELETE, GET, OPTIONS
  • Access-Control-Allow-Origin: *

我是否遗漏了一些步骤? 我在控制器上尝试了以下注释:

[EnableCors(origins: "http://example.com", headers: "*", methods: "*")]

同样的结果,没有启用 CORS。

然而,如果我在 web.config 中添加以下内容(甚至不需要安装 AspNet.WebApi.Cors 依赖项) ,它就可以工作:

<system.webServer>


<httpProtocol>
<!-- THESE HEADERS ARE IMPORTANT TO WORK WITH CORS -->
<!--
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="POST, PUT, DELETE, GET, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="content-Type, accept, origin, X-Requested-With, Authorization, name" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
-->
</httpProtocol>
<handlers>
<!-- THESE HANDLERS ARE IMPORTANT FOR WEB API TO WORK WITH  GET,HEAD,POST,PUT,DELETE and CORS-->
<!--


<remove name="WebDAV" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,PUT,DELETE" 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>

任何帮助都将不胜感激!

谢谢你。

113456 次浏览

In case of CORS request all modern browsers respond with an OPTION verb, and then the actual request follows through. This is supposed to be used to prompt the user for confirmation in case of a CORS request. But in case of an API if you would want to skip this verification process add the following snippet to Global.asax

        protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, PUT, DELETE");


HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}

Here we are just by passing the check by checking for OPTIONS verb.

I've created a pared-down demo project for you.

You can try the above API Link from your local Fiddler to see the headers. Here is an explanation.

Global.ascx

All this does is call the WebApiConfig. It's nothing but code organization.

public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
}
}

WebApiConfig.cs

The key method for your here is the EnableCrossSiteRequests method. This is all that you need to do. The EnableCorsAttribute is a globally scoped CORS attribute.

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
EnableCrossSiteRequests(config);
AddRoutes(config);
}


private static void AddRoutes(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/"
);
}


private static void EnableCrossSiteRequests(HttpConfiguration config)
{
var cors = new EnableCorsAttribute(
origins: "*",
headers: "*",
methods: "*");
config.EnableCors(cors);
}
}

Values Controller

The Get method receives the EnableCors attribute that we applied globally. The Another method overrides the global EnableCors.

public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] {
"This is a CORS response.",
"It works from any origin."
};
}


// GET api/values/another
[HttpGet]
[EnableCors(origins:"http://www.bigfont.ca", headers:"*", methods: "*")]
public IEnumerable<string> Another()
{
return new string[] {
"This is a CORS response. ",
"It works only from two origins: ",
"1. www.bigfont.ca ",
"2. the same origin."
};
}
}

Web.config

You do not need to add anything special into web.config. In fact, this is what the demo's web.config looks like - it's empty.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
</configuration>

Demo

var url = "https://cors-webapi.azurewebsites.net/api/values"


$.get(url, function(data) {
console.log("We expect this to succeed.");
console.log(data);
});


var url = "https://cors-webapi.azurewebsites.net/api/values/another"


$.get(url, function(data) {
console.log(data);
}).fail(function(xhr, status, text) {
console.log("We expect this to fail.");
console.log(status);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

I just experienced this same issue, trying to enable CORS globally. However I found out it does work, however only when the request contains a Origin header value. If you omit the origin header value, the response will not contain a Access-Control-Allow-Origin.

I used a chrome plugin called DHC to test my GET request. It allowed me to add the Origin header easily.

None of these answers really work. As others noted the Cors package will only use the Access-Control-Allow-Origin header if the request had an Origin header. But you can't generally just add an Origin header to the request because browsers may try to regulate that too.

If you want a quick and dirty way to allow cross site requests to a web api, it's really a lot easier to just write a custom filter attribute:

public class AllowCors : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext == null)
{
throw new ArgumentNullException("actionExecutedContext");
}
else
{
actionExecutedContext.Response.Headers.Remove("Access-Control-Allow-Origin");
actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
}
base.OnActionExecuted(actionExecutedContext);
}
}

Then just use it on your Controller action:

[AllowCors]
public IHttpActionResult Get()
{
return Ok("value");
}

I won't vouch for the security of this in general, but it's probably a lot safer than setting the headers in the web.config since this way you can apply them only as specifically as you need them.

And of course it is simple to modify the above to allow only certain origins, methods etc.

I found this question because I was having issues with the OPTIONS request most browsers send. My app was routing the OPTIONS requests and using my IoC to construct lots of objects and some were throwing exceptions on this odd request type for various reasons.

Basically put in an ignore route for all OPTIONS requests if they are causing you problems:

var constraints = new { httpMethod = new HttpMethodConstraint(HttpMethod.Options) };
config.Routes.IgnoreRoute("OPTIONS", "{*pathInfo}", constraints);

More info: Stop Web API processing OPTIONS requests

Hope this helps someone in the future. My problem was that I was following the same tutorial as the OP to enable global CORS. However, I also set an Action specific CORS rule in my AccountController.cs file:

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

and was getting errors about the origin cannot be null or empty string. BUT the error was happening in the Global.asax.cs file of all places. Solution is to change it to:

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

notice the * in the origins? Missing that was what was causing the error in the Global.asax.cs file.

Hope this helps someone.

You just need to change some files. This works for me.

Global.ascx

public class WebApiApplication : System.Web.HttpApplication {
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
} }

WebApiConfig.cs

All the requests has to call this code.

public static class WebApiConfig {
public static void Register(HttpConfiguration config)
{
EnableCrossSiteRequests(config);
AddRoutes(config);
}


private static void AddRoutes(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/"
);
}


private static void EnableCrossSiteRequests(HttpConfiguration config)
{
var cors = new EnableCorsAttribute(
origins: "*",
headers: "*",
methods: "*");
config.EnableCors(cors);
} }

Some Controller

Nothing to change.

Web.config

You need to add handlers in your web.config

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

I just added custom headers to the Web.config and it worked like a charm.

On configuration - system.webServer:

<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>

I have the front end app and the backend on the same solution. For this to work, I need to set the web services project (Backend) as the default for this to work.

I was using ReST, haven't tried with anything else.

WEBAPI2:SOLUTION. global.asax.cs:

var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);

IN solution explorer, right-click api-project. In properties window set 'Anonymous Authentication' to Enabled !!!

Hope this helps someone in the future.

After some modifications in my Web.config CORS suddenly stopped working in my Web API 2 project (at least for OPTIONS request during the preflight). It seems that you need to have the section mentioned below in your Web.config or otherwise the (global) EnableCorsAttribute will not work on OPTIONS requests. Note that this is the exact same section Visual Studio will add in a new Web API 2 project.

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

No-one of safe solution work for me so to be safer than Neeraj and easier than Matthew just add: System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");

In your controller's method. That work for me.

public IHttpActionResult Get()
{
System.Web.HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
return Ok("value");
}