Web API 2 CORS预飞行选项请求失败,错误504

时间:2016-05-23 18:39:07

标签: angularjs asp.net-web-api cors preflight

我有一个Web API 2项目,需要从单独的域访问。 GET请求工作正常,但POST失败并带有预先飞行请求。我无法让OPTIONS请求正确返回。

我已将NuGet包Microsoft.AspNet.WebApi.Cors添加到项目中。

在WebApiConfig.cs中,我打电话给:

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

我的Web.config包含以下值:

 <system.webServer>
    <modules>
      <remove name="FormsAuthentication" />
    </modules>
    <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>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,OPTIONS" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>

在global.asax.cs中我添加了:

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

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

在Fiddler中,我看到了

的请求
  

OPTIONS / api / app / controller HTTP / 1.1

但回复是

  

HTTP / 1.1 504 Fiddler - 接收失败

当AngularJS发出请求时,它有以下标题:

Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:4104
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
Access-Control-Request-Headers: accept, content-type
Accept: */*
Referer: http://localhost:4104/index.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6

如果我使用具有相同标头的高级REST客户端的Chrome插件,它也会失败。但是,如果我删除标题Access-Control-Request-Method: POST,我会从OPTIONS请求中返回200响应。

更新

将Global.asax.cs代码更改为

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("Cache-Control", "no-cache");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "OPTIONS, GET, POST");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.Flush();
        HttpContext.Current.Response.SuppressContent = true;
        HttpContext.Current.ApplicationInstance.CompleteRequest();
    }
}

从Chrome Advanced REST客户端发出请求时,我收到了200响应代码。但是,我仍然从调用web api的角度代码中看到完全相同的超时。

这是AngularJs代码:

$http({
    method: 'POST',
    url: 'http://www.test.com/api/app/controller',
    data: postdata,
    headers: {
        'Content-Type': 'application/json'
    }
})
.then(function(response) {
    // Do stuff
}, function() {
    // Show error
})
.finally(function() {
    // Cancel loading indicator
});

我已更改Application_BeginRequest的第一行以包含日志记录:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    log.Debug("Application_BeginRequest " + HttpContext.Current.Request.HttpMethod);

对于GET请求,请记录Application_BeginRequest GET。从AngularJS发出OPTIONS请求时,不会记录任何内容。看起来似乎永远无法访问代码Application_BeginRequest。当我使用Chrome Advanced REST API从同一台计算机拨打电话时,它会记录(并且可以正常工作)。

1 个答案:

答案 0 :(得分:2)

使用Global.asax

中的Application_BeginRequest手动添加标头
  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("Cache-Control", "no-cache");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
                HttpContext.Current.Response.End();
            }
        }