科尔多瓦在某些Android设备上未根据请求发送原始信息

时间:2019-08-02 12:20:43

标签: android cordova cors android-webview cordova-plugins

这是某些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-Policycordova-whitelist-plugin的配置不会有问题,因为正如我之前提到的,在其他一些Android设备上,该应用程序也可以正常工作。

我需要提到的其他事情是,使用人行横道插件时我没有这个问题。

3 个答案:

答案 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中签入冷启动标志。如果找不到,请重新启动应用程序。