在 Azure Web 应用程序/Azure API 上部署时缺少 CORS headers

CORS headers missing when deployed on Azure Web App / Azure API

我创建了一个 OWIN 托管 WebAPI 2。还有一个网络应用程序 (AngularJS) 使用 API 并充当客户端。

我已将 CORS 的必要代码添加到 Startup.cs,并将其托管在与客户端不同的端口上的本地 IIS 中,并确认它修复了 Cors 问题。

然后,我将这两个应用程序都部署到 Azure(我已经将它们作为 Web 应用程序放在 Azure 上,我还尝试将 OWIN 放到目前处于预览状态的 Azure API)但是 -预检请求现在失败(响应中没有 Access-Control-Allow-Origin)。

问: Azure 有什么我不知道的吗?为什么 OWIN 在部署时不提供这个 header 但它在本地主机上工作?我在应用程序的 Azure 刀片设置的属性 window 中没有看到任何限制。

备注:

关于我正在使用的设置的一些细节:

Startup.cs的相关部分:

public void Configuration(IAppBuilder appBuilder)
{
    appBuilder.UseCors(CorsOptions.AllowAll);

    HttpConfiguration config = new HttpConfiguration();
    config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

    //bind IClientsNotifier with method returning singleton instance of hub
    var ninjectKernel = NinjectWebCommon.GetKernel();
    ninjectKernel.Bind<MySignalRHub>().ToSelf().InSingletonScope();
    ninjectKernel.Bind<QueryStringBearerAuthorizeAttribute>().ToSelf();

    GlobalHost.DependencyResolver = new NinjectSignalRDependencyResolver(ninjectKernel);
    appBuilder.Map(
        "/signalr", map =>
    {
        map.UseCors(CorsOptions.AllowAll);
        var hubConfiguration = new HubConfiguration();
        map.RunSignalR(hubConfiguration);
    });

    config.MapHttpAttributeRoutes();

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

    config.Formatters.Remove(config.Formatters.XmlFormatter);

    config.Filters.Add(new NoCacheHeaderFilter()); //the IE9 fix for cache
    var resolver = new NinjectDependencyResolver(NinjectWebCommon.GetKernel());

config.Filters.Add((System.Web.Http.Filters.IFilter)resolver.GetService(typeof(WebApiAuthenticationFilter)));

    appBuilder.UseNinjectMiddleware(NinjectWebCommon.GetKernel);
    appBuilder.UseNinjectWebApi(config);
}

此外,为了支持 OPTIONS HTTP 请求(否则,它会抛出 HTTP 错误 405)

,我从 web.config 中注释掉了以下行
<system.webServer>
   <handlers>
     <!--<remove name="OPTIONSVerbHandler" />-->
     ...

最后我采用了更简单的方法 - 删除了 CORS 的所有 code-handling 并简单地将 headers 放在 web.config:

<configuration>
 <system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="http://my-client-website.azurewebsites.net" />
      <add name="Access-Control-Allow-Methods" value="*" />
      <add name="Access-Control-Allow-Headers" value="accept, content-type, x-my-custom-header" />
      <add name="Access-Control-Allow-Credentials" value="true" />
    </customHeaders>
  </httpProtocol>
 ...

(注意 allow-origin 在 url 末尾没有斜杠!)

allow-credentials部分是为了满足SignalR,可能没有它也行。

如果有人找到编码方式不起作用的原因,我想知道!

实际上,Azure 网站应该为您管理 CORS。我想你错过了一个方便的 Azure 网站 blade:

如果我们自己的理解是正确的,这个 Azure 中间件的问题是它允许你配置允许的来源。它缺少 "allowed headers" 可管理的配置、per-URL 规则和其他有用的 CORS HTTP headers。更糟糕的是:它会从它处理的每个 HTTP 响应中删除所有与 CORS 相关的 headers,然后再设置自己的响应,因此它甚至不允许您处理它不处理的内容。

好处是您可以完全禁用此中间件并通过自己的方式管理 CORS,您只需从 CORS 设置中删除每个允许的源(包括 *)blade在门户中。那么可以使用web.config或者WebApi来更具体的处理。参见 the documentation

Don't try to use both Web API CORS and App Service CORS in one API app. App Service CORS will take precedence and Web API CORS will have no effect. For example, if you enable one origin domain in App Service, and enable all origin domains in your Web API code, your Azure API app will only accept calls from the domain you specified in Azure.

另见 this related issue:

So the final answer is: If your application does not need a very specific CORS management, you can use Azure App Service CORS. Otherwise you will need to handle it yourself and disable all CORS configuration in the web app.

我在 Azure 门户上设置了这个,但是 chrome 跨域请求的预检仍然失败。在 Azure 文档中,预检使用 OPTION http 动词,我猜 chrome 可能只使用 GET,所以没有 header 值。

我也 运行 关注这个问题。我想我终于让程序化的 WebAPI 的 CORS 在 Azure 应用程序服务中工作,具有处理程序更改的这种神奇组合:

  <remove name="OPTIONSVerbHandler" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,POST,PUT,DELETE,HEAD,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

do 必须删除 OPTIONSVerbHandler 以摆脱默认的预检响应——通过在 web.config 中使用自定义 headers,您只需找到了另一种方法来确保那些 headers 被写入那些永远不会到达您的应用程序的 OPTIONS 请求。

关键是确保其他东西负责 OPTIONS 请求,我相信这是通过 re-adding 在动词列表中指定 OPTIONS 的 ExtensionlessUrlHandler 实现的。我不太精通 IIS,所以我在推测该机制,但它似乎确实有效。 FWIW,这是我在 App_Start/WebApiConfig.cs 中启动 WebAPI 的 CORS 功能,如下所示:

config.EnableCors(new MyCorsPolicyProvider());

其中 MyCorsPolicyProvider 是实现 ICorsPolicyProvider 的 class。

我的问题是我不小心将 http 而不是 https 放入 Azure AD B2C 自定义页面配置 blade ...更改为 https 后,它就像一个魅力。

在 AZURE 云上尝试此命令 shell

Azure cloud shell

az resource update --name web --resource-group ***1*** --namespace Microsoft.Web --resource-type config --parent sites/***2*** --set properties.cors.allowedOrigins="['http://localhost:5000']" --api-version 2015-06-01

****1**** = 您的资源组名称

****2**** = 您的应用名称