これは一部の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デバイスでは、アプリケーションが正常に動作するためです。
私が言及する必要がある他の何かは、横断歩道プラグインで私はこの問題を持っていなかったことです。
同じ問題が発生しています。最初に、アプリがChrome=バージョンを検出する回避策を実装しました。最初にバージョン76が表示されると、アプリが自動的に再起動されます。ほとんどのユーザーは、再起動に気付くことすらありません。回避策はいくつかのレポートに基づいて、問題はChroe 76がインストールされた後のアプリの最初の実行中にのみ発生し、再起動後に完全に消えるであろうと判明しました。しかし、問題はしばしばランダムに見えるようになりました。十分ではなかった。
幸いにもサーバー側を制御しているので、そこで回避策を実装しました。基本的には、file://
Originを受け入れるだけです。この回避策のセキュリティへの影響は、確かに個々のアプリケーションに依存するため、同様のものの実装を検討する場合に備えて、慎重に検討してください。
今回のケースでは、追加の課題に直面していたASP.NETを使用しています。残念ながら、file://
をオリジンとして指定すると、EnableCorsAttribute
は失敗します。これは、各オリジンにホスト名が存在する必要があるCORS仕様に準拠しています(*
を指定する場合を除く)。したがって、最終的に次のソリューションを思いついた(もちろんASP.NETに固有)。
Origin file://
の場合は検証ロジックをオーバーライドし、他のすべての場合はネストされたプロバイダー(元のプロバイダー)に委任するICorsPolicyProvider
を作成します。
/// <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);
これは、76バージョンに興味深いChromium webviewの未解決のバグです。この特定のバージョンでは、OOR-CORSは最初の実行では有効のままです。
https://bugs.chromium.org/p/chromium/issues/detail?id=991107#c14
変更リストは76ブランチに直接マージされます。
同じ問題が発生しています... AJAXコールは、Cordovaプロジェクトの最初のコールドスタート後に機能しません。アプリを再起動すると(アプリをバックグラウンドから削除)、機能します。 。ChromiumWebViewバージョンに問題があるようです...非常に醜い回避策を見つけました。
https://github.com/dpa99c/cordova-diagnostic-plugin#restart
プラグインし、最初のコールドスタート後にアプリを再起動します。コールドスタートフラグのlocalStorageを確認します。見つからない場合は、アプリを再起動してください。