这是某些Android设备上发生的问题。
我有一个Samsung Galaxy A5 (2017)
的Google Chrome version 76.0.3809.89
和Android版本8.0.0。
当我第一次在此设备上部署Cordova应用程序并发出POST请求时,收到关于CORS的错误:
Access to XMLHttpRequest at 'http://foo.com/bar' from origin 'file://' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
我从Chrome的开发工具网络标签中看到,该POST请求没有origin
参数。
如果我从任务管理器中关闭该应用程序,然后再次启动它,则我可以成功发出此请求,然后chrome根据请求发送“ origin”参数。
如果我从设备的设置中删除了应用程序的数据,我可以再次重现该问题。
我完全确定Content-Security-Policy
或cordova-whitelist-plugin
的配置不会有问题,因为正如我之前提到的,在其他一些Android设备上,该应用程序也可以正常工作。
我需要提到的其他事情是,使用人行横道插件时我没有这个问题。
答案 0 :(得分:7)
这是Chromium Webview上的一个开放式错误,有趣的是76版本;在此特定版本中,OOR-CORS在首次运行时保持启用状态。
https://bugs.chromium.org/p/chromium/issues/detail?id=991107#c14
更改列表将直接合并到76个分支中。
答案 1 :(得分:2)
我们遇到了同样的问题。我们首先尝试实施一种解决方法,使该应用检测到Chrome版本。第一次看到版本76时,它将自动重新启动应用程序。大多数用户甚至都不会注意到重启。解决方法基于几份报告,这些报告指出,问题仅在安装Chroe 76之后才在应用程序的第一次运行期间出现,并在重新启动后永久消失。但是,事实证明,问题通常看起来似乎是随机出现的,因此解决方法还不够。
幸运的是,我们也可以控制服务器端,因此我们在此处实施了变通方法。基本上,我们只接受file://
的起源。这种解决方法的安全性影响当然取决于各个应用程序,因此请仔细考虑一下,以防您考虑实现类似的东西。
在我们的案例中,我们使用的是ASP.NET,我们面临着另一个挑战。不幸的是,EnableCorsAttribute
在将file://
指定为来源时失败,这符合CORS规范,CORS规范要求在每个来源中都存在一个主机名(指定*
时除外)。因此,我们最终提出了以下解决方案(当然是特定于ASP.NET的):
创建一个ICorsPolicyProvider
,以在源file://
的情况下覆盖验证逻辑,并在所有其他情况下委托给嵌套提供者(原始提供者):
/// <summary>
/// Object that allows clients with `file://` origin. This is used as a workaround
/// for issues on Android devices running Chrome 76. See
/// https://bugs.chromium.org/p/chromium/issues/detail?id=991107#c14
///
/// Simply adding `file://` to the allowed origins list doesn't work, because by
/// specification a hostname is required.
///
/// This workaround should be removed as soon as Chrome 76 distribution has dropped
/// sufficiently.
/// </summary>
// TODO: Remove this workaround once Chrome 76 is not around anymore.
public class CorsPolicyProviderAcceptingFileOrigin : ICorsPolicyProvider
{
public readonly ICorsPolicyProvider inner;
public CorsPolicyProviderAcceptingFileOrigin(ICorsPolicyProvider inner)
{
this.inner = inner;
}
public async Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (
request.Headers.TryGetValues("origin", out IEnumerable<string> origins)
&& origins.SequenceEqual(new[] { "file://" })
)
{
var policy = new CorsPolicy()
{
AllowAnyHeader = true,
AllowAnyMethod = true,
AllowAnyOrigin = false,
};
policy.Origins.Add("file://");
return policy;
}
return await this.inner.GetCorsPolicyAsync(request, cancellationToken);
}
}
,然后在WebApiConfig.cs
中像这样使用它:
// get the original EnableCorsAttribute
ICorsPolicyProvider cors = ...;
// this is a workaround for Android devices running Chrome 76 and should be removed in future versions.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=991107
cors = new CorsPolicyProviderAcceptingFileOrigin(cors);
config.EnableCors(cors);
答案 2 :(得分:0)
我们也遇到了同样的问题... Cordova项目中的第一个冷启动后,AJAX调用将不起作用。如果我们重新启动应用程序(从后台删除应用程序),那么它将起作用... Chromium WebView版本似乎有问题...我发现了一个非常难看的解决方法。使用
https://github.com/dpa99c/cordova-diagnostic-plugin#restart
插件,并在第一次冷启动后重新启动应用程序。在localStorage中签入冷启动标志。如果找不到,请重新启动应用程序。