部署在Azure Web App / Azure API上时缺少CORS标头
我创建了一个OWIN托管的WebAPI 2
。 还有一个Web应用程序( AngularJS
),它使用API并充当客户端。
我已经将必要的CORS
代码添加到Startup.cs
,并将其托管在不同于客户端的端口上的本地IIS中,并确认它修复了Cors
问题。
然后,我将这两个应用程序部署到Azure(我已将两者都放在Azure上作为Web应用程序,我也尝试将OWIN放到当前处于预览状态的Azure API中)但是 – 预检请求现在失败了(没有Access-Control-Allow-Origin
出现在响应中)。
问:我不知道Azure的某些特定内容吗? 为什么OWIN在部署时没有提供此标头,但是它正在使用localhost? 我在应用程序的Azure刀片设置的属性窗口中看不到任何约束。
笔记:
关于我正在使用的设置的一些细节:
- 使用
Owin
,WebAPI2
,Ninject
,SignalR
- 在每个后续请求的头文件中发布并提供自定义令牌,并使用自定义filter进行validation。
- 我现在正在尝试的是
*
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().ToSelf().InSingletonScope(); ninjectKernel.Bind().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); }
另外,我已经从web.config
注释掉了以下行,以便支持OPTIONS
HTTP请求(否则,它会抛出HTTP错误405)
<!----> ...
实际上,Azure网站应该为您管理CORS。 我想你错过了一个方便的Azure网站刀片:
如果我们自己的理解是正确的,那么这个Azure中间件的问题是,它允许您配置除允许的起源之外的任何内容。 它缺少“允许标头”可管理配置,每URL规则和其他有用的CORS HTTP标头。 更糟糕的是:它会在设置自己的每个HTTP响应之前丢弃所有与CORS相关的标头,因此它甚至不能让你处理它没有的内容。
好处是您可以完全禁用此中间件并通过自己的方式管理CORS,您必须从门户中的CORS设置刀片中删除每个允许的来源(包括*
)。 然后,您可以使用web.config或Web Api更具体地处理它。 查看文档 :
不要尝试在一个API应用程序中同时使用Web API CORS和App Service CORS。 App Service CORS优先,Web API CORS不起作用。 例如,如果在App Service中启用一个源域,并在Web API代码中启用所有源域,则Azure API应用程序将仅接受来自您在Azure中指定的域的调用。
另见相关问题 :
因此,最终的答案是:如果您的应用程序不需要非常具体的CORS管理,则可以使用Azure App Service CORS。 否则,您将需要自己处理它并禁用Web应用程序中的所有CORS配置。
最后,我采用了更简单的方法 – 删除了CORS
所有代码处理,只需将标头放在web.config
:
...
(注意,allow-origin在url的末尾没有斜杠!)
allow-credentials部分是为了满足SignalR,可能没有它。
如果有人找到原因,为什么编码方式不起作用,我想知道!
我也遇到过这个问题。 我想我终于通过这种神奇的处理程序更改组合在Azure App Service中运行程序化的WebAPI CORS:
您必须删除OPTIONSVerbHandler才能摆脱默认的预检响应 – 通过在web.config中使用自定义标头,您只需找到另一种方法来确保将这些标头写入那些从未到达您应用的OPTIONS请求。
关键是确保其他东西负责OPTIONS请求,我相信通过在动词列表中重新添加指定OPTIONS的ExtensionlessUrlHandler来实现。 我不熟悉IIS,所以我猜测机制,但它似乎确实有用。 FWIW,这是我在App_Start / WebApiConfig.cs中调整WebAPI的CORSfunction,如下所示:
config.EnableCors(new MyCorsPolicyProvider());
其中MyCorsPolicyProvider
是一个实现ICorsPolicyProvider
的类。
我在azure portal上设置了这个,但是对于跨域请求,chrome预检仍然失败。 在azure文档中,预检使用OPTION http动词,我猜chrome可能只使用GET,因此没有标题值。
我的问题是我不小心将http而不是https放入Azure AD B2C自定义页面配置刀片……更改为https后,它就像一个魅力。
在AZURE云shell上尝试此命令
Azure云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 **** =您的应用名称