在Web API 2中启用CORS

79

我有一个客户端和服务器在不同的端口上运行。服务器正在运行Web API 2 (v5.0.0-rc1)

我尝试安装Microsoft ASP.NET Web API跨源支持包并在WebApiConfig.cs中启用它。它给了我EnableCors()函数,所以包已正确安装。

您可以在此处查看我的WebApiConfig.cs中的Register()函数:

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

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

GET请求工作正常。但是发送POST时,我收到以下错误:

OPTIONS http://localhost:19357/api/v1/rooms? 404 (Not Found) angular.js:10159
OPTIONS http://localhost:19357/api/v1/rooms? Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin. angular.js:10159
XMLHttpRequest cannot load http://localhost:19357/api/v1/rooms. Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin.

根据Fiddler的记录,它只发送了OPTIONS请求。之后并没有发起POST请求。

因此我猜测在WebApiConfig.cs中的config.EnableCors(cors);并没有发挥作用,这导致服务器拒绝了客户端/浏览器发送POST请求。

你有任何解决这个问题的想法吗?

编辑 05.09.13 此问题已在5.0.0-rtm-130905版本中得到修复。


谢谢您的问题和答案,已经在5.0.0-rtm中修复。我在哪里可以获取RTM版本? - Jaans
1
工具 -> 库包管理器 -> 包管理器设置,并在“包源”下添加以下URL: http://www.myget.org/F/aspnetwebstacknightly/ - Gaui
11个回答

84

Microsoft.AspNet.WebApi.Cors版本5.2.2中的CORS可以完美运行。以下步骤可以像魔术般为我配置CORS:

  1. Install-Package Microsoft.AspNet.WebApi.Cors -Version "5.2.2" // 从包管理器控制台运行
  2. 在Global.asax中,在任何MVC路由注册之前添加以下行:

GlobalConfiguration.Configure(WebApiConfig.Register);
WebApiConfig 的 Register 方法中,添加以下代码:
public static void Register(HttpConfiguration config)
{
    config.EnableCors();
    config.MapHttpAttributeRoutes();
}
在web.config中,以下处理程序必须是管道中的第一个:

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

在派生自ApiController的控制器中,添加EnableCorsAttribute

[EnableCors(origins: "*", headers: "*", methods: "*")] // tune to your needs
[RoutePrefix("")]
public class MyController : ApiController

那应该很好地为你设置了!


就像我说的那样,它在5.0.0-rtm-130905版中被修复了 :) - Gaui
当然,我只是为了完整性而添加了这些步骤 :) - Sudhanshu Mishra
3
我想补充一点,我希望启用跨域资源共享(CORS),但仅在控制器/操作级别上启用。 我不想全局开放它。但是,除非我在WebApiConfig中添加了config.EnableCors(),否则没有任何效果...基本上启用它,但不使用参数。但是,这样我就可以在单个控制器/操作级别上使用[System.Web.Http.Cors.EnableCors(origins: "", headers: "", methods: "*")]。 - da_jokker
不要忘记添加 using System.Web.Http.Cors; - AIMEN BOULAHIA
我必须先删除ExtensionlessUrlHandler-Integrated-4.0,然后再重新添加它。所以这对我有用 - <remove name="ExtensionlessUrlHandler-Integrated-4.0" /> <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" /> - Rohit Singh
显示剩余4条评论

66

5
这个方法很有用,但如果你想按控制器/路由的方式指定CORS时它就不起作用了。 - Gaui
2
由于您建议的是我在项目中使用的相同技巧,所以加一分!并且讨厌NuGet包,它完全是不必要的!愉快编码,兄弟! - Kevin Simple
1
这种方法还有一个注意事项:对于OWIN/Katana,您可能没有托管在IIS中,因此就没有web.config文件 - 这就是为什么要使用Microsoft.AspNet.WebApi.Cors包的原因。 - Sudhanshu Mishra
3
这种方法的另一个缺点是会导致标头包含在服务器返回的_每个_响应中。Microsoft.AspNet.WebApi.Cors只有在请求包含Origin:标头时才知道要包含它。 - Tyler
它似乎是最简单的方法,但并不总是有效,就像所有CORS方法一样。 - Svend

11
作为参考,如果您使用[EnableCors()]方法拦截消息管道,将不起作用。在我的情况下,我会在路由被调用之前检查请求中的Authorization标头并相应处理,这意味着我的请求在管道中更早地被处理,因此[EnableCors()]没有效果。
最终我找到了一个示例CrossDomainHandler(感谢shaunxuGist),它可以在管道中为我处理CORS,只需要添加另一个消息处理程序即可。
public class CrossDomainHandler : DelegatingHandler
    {
        const string Origin = "Origin";
        const string AccessControlRequestMethod = "Access-Control-Request-Method";
        const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
        const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";
        const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
        const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            bool isCorsRequest = request.Headers.Contains(Origin);
            bool isPreflightRequest = request.Method == HttpMethod.Options;
            if (isCorsRequest)
            {
                if (isPreflightRequest)
                {
                    return Task.Factory.StartNew(() =>
                    {
                        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
                        response.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());

                        string accessControlRequestMethod = request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault();
                        if (accessControlRequestMethod != null)
                        {
                            response.Headers.Add(AccessControlAllowMethods, accessControlRequestMethod);
                        }

                        string requestedHeaders = string.Join(", ", request.Headers.GetValues(AccessControlRequestHeaders));
                        if (!string.IsNullOrEmpty(requestedHeaders))
                        {
                            response.Headers.Add(AccessControlAllowHeaders, requestedHeaders);
                        }

                        return response;
                    }, cancellationToken);
                }
                else
                {
                    return base.SendAsync(request, cancellationToken).ContinueWith(t =>
                    {
                        HttpResponseMessage resp = t.Result;
                        resp.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());
                        return resp;
                    });
                }
            }
            else
            {
                return base.SendAsync(request, cancellationToken);
            }
        }
    }

要使用它,请将其添加到已注册消息处理程序的列表中。

config.MessageHandlers.Add(new CrossDomainHandler());

浏览器发出的任何预检请求都将得到处理并传递,这意味着我不需要在控制器上实现[HttpOptions] IHttpActionResult方法。


1
这让我遇到了一个与ASP .NET Web API CORS策略有关的问题,相关的响应没有返回。结果发现它是基于FilterAttribute实现的,不像管道的DelegatingHandler阶段那样早参与。因此,如果处理程序提前返回,您必须手动提供CORS标头响应(并根据您的策略)。 - Jaans

7

请确保您通过HTTPS访问WebAPI。

我还在WebApi.config中启用了跨源资源共享(CORS)。

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

直到我使用 HTTPS URL 才成功进行 CORS 请求。


7

5
这解决了我的问题:
在Web.config文件中,位于system.webServer标签内:
 <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
            <add name="Access-Control-Allow-Methods" value="GET,POST,PUT, DELETE, OPTIONS" />
            <add name="Access-Control-Allow-Headers" value="*" />
            <add name="Access-Control-Allow-Credentials" value="true" />
        </customHeaders>
    </httpProtocol>

取消注释或删除 system.webServer 中的此行:

<remove name="OPTIONSVerbHandler"/>

此外,您需要在webapiconfig.cs或web.config文件中声明启用cors。如果同时在两者中都声明,您可能会遇到类似以下的错误:
'....origin 'www.example.com' blocked by cors policy due to multiple No 'Access-Control-Allow-Origin'('*','*').'

这对我起了作用。


4

迟来的回复,请留作参考。使它工作的方法是使用NuGet启用它,然后在web.config中添加自定义标头。


谢谢!通过包管理控制台安装一直无法正常工作,所以我尝试了通过NuGet界面安装,它自动更新了项目引用,并且现在可以正常工作了。 - user441058

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

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

1
为了启用CORS, 1.进入App_Start文件夹。 2.添加命名空间'using System.Web.Http.Cors'; 3.打开WebApiConfig.cs文件,在静态方法中键入以下内容。

config.EnableCors(new EnableCorsAttribute("https://localhost:44328",headers:"*", methods:"*"));


0

以下代码对我有效:

App_Start -> WebApiConfig

EnableCorsAttribute cors = new EnableCorsAttribute("\*", "\*", "GET,HEAD,POST");
config.EnableCors(cors);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接