Cordova不会在某些Android设备中按要求发送来源 [英] Cordova doesn't send origin on request in some Android devices

查看:90
本文介绍了Cordova不会在某些Android设备中按要求发送来源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是某些Android设备上发生的问题.

This is a problem that happens on some android devices.

我有一个Samsung Galaxy A5 (2017)和Google Chrome version 76.0.3809.89和Android 8.0.0版.

I have a Samsung Galaxy A5 (2017) with Google Chrome version 76.0.3809.89 and Android version 8.0.0.

当我第一次在此设备上部署Cordova应用程序并发出POST请求时,收到关于CORS的错误:

When I deploy my Cordova application for the first time on this device and making a POST request I receive an error about 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参数.

I can saw from Chrome's dev tool network tab that this POST request, doesn't have the origin parameter.

如果我从任务管理器中关闭该应用程序,然后再次启动它,则我可以成功发出此请求,然后chrome根据请求发送"origin"参数.

If I close the application from the task manager and starting it again I can make this request successfully and chrome sends the 'origin' parameter on request.

如果我从设备的设置中删除了应用程序的数据,我可以再次重现该问题.

I can re-produce the problem again if I delete applications' data from device's settings.

我完全确定Content-Security-Policycordova-whitelist-plugin配置不是问题,因为正如我之前提到的,在其他一些android设备上,该应用程序也可以正常工作.

I'm totally sure that this is not a problem with Content-Security-Policy or cordova-whitelist-plugin configuration because as I mention before, on some other android devices the application works just fine.

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

Something other that I need to mention is that with crosswalk plugin I didn't have this problem.

推荐答案

我们遇到了同样的问题.我们首先尝试实施一种变通方法,其中该应用程序检测到Chrome版本.第一次看到版本76时,它将自动重新启动应用程序.大多数用户甚至都不会注意到重启.解决方法基于几份报告,这些报告指出,该问题仅在安装Chroe 76之后才在应用程序的第一次运行中出现,并在重新启动后永久消失.但是,事实证明,问题通常是随机出现的,因此解决方案还不够.

We're experiencing the same issue. We first tried to implement a workaround where the App detects the Chrome version. The first time it sees version 76 it automatically restarts the app. Most users wouldn't even notice the restart. The workaround was based on several reports which stated, that the problem would only appear during the first run of the app after Chroe 76 had been installed and permanently disappear after a restart. However, it turned out, that the problem often returns seemingly randomly, so the woraround wasn't sufficient.

幸运的是,我们也可以控制服务器端,因此我们在此处实施了变通方法.基本上,我们只接受file://起源.这种解决方法的安全性影响当然取决于单个应用程序,因此请仔细考虑一下,以防您考虑实现类似的东西.

Luckily we're in control of the server side too, so we implemented a workaround there. Basicly we simply accept the file:// origin. The security impact of this workaround certainly depends on the individual application, so think about it carefully in case you consider implemeinting something similar.

在我们的案例中,我们使用的是ASP.NET,我们面临着另一个挑战.不幸的是,EnableCorsAttribute在将file://指定为来源时失败,这与CORS规范一致,CORS规范要求在每个来源中都存在一个主机名(指定*时除外).因此,我们终于提出了以下解决方案(当然是特定于ASP.NET的):

In our case we're using ASP.NET where we were facing an additional challenge. Unfortunately EnableCorsAttribute fails when specifying file:// as an origin, which is in line with the CORS specification, which requires a hostname to be present in each origin (except when specifying *). So we finally came up with the following solution (specific to ASP.NET of course):

在源为file://的情况下创建一个覆盖验证逻辑的ICorsPolicyProvider,并在所有其他情况下委托给嵌套提供者(原始提供者):

Create an ICorsPolicyProvider that overrides the validation logic in case of origin file:// and delegates to a nested provider (the original one) in all other cases:

    /// <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中像这样使用它:

and then use it like this in 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);

这篇关于Cordova不会在某些Android设备中按要求发送来源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆