問題の内容
ブラウザのコンソールウィンドウに、次のいずれかのメッセージが表示されます。
- Failed to load ...No 'Access-Control-Allow-Origin' header
- Cross-Origin Request Blocked:The Same Origin Policy disallows reading the remote resource ...Reason:CORS header 'Access-Control-Allow-Origin' missing
- Failed to load ...Response to preflight request doesn't pass access control check:No 'Access-Control-Allow-Origin' header present on the requested resource.Origin ... is therefore not allowed access
これらのメッセージでは通常、「Access-Control-Allow-Origin
」というキーワードが表示されます。
条件
ブラウザベースのWebアプリケーション(アプリフレームワークのアプリなど)が、外部Webサービスから共有リソースを取得するために、クロスオリジン呼び出しを実行しようとします。これは、CORSリクエスト(オリジン間リソース共有)と呼ばれます。
このようなオリジン間のコールを管理するブラウザベースのCORS標準があります。特定の条件が満たされていない場合に、上記のようなエラーが発生します。
解決策
これは、必ずしもバグであるとは限りません。ユーザーのWebアプリケーションとリモートの外部サービスによって意図的に禁止されている可能性があります。
1つのオリジン(www.origin1.com)が別のオリジン(www.origin2.com)を呼び出した場合、これを「オリジン間リクエスト」と呼びます。このリクエストを機能させるには、特定の条件を設定する必要があります。呼び出される外部サービス(www.origin2.com)は、応答としてHTTPヘッダー「Access-Control-Allow-Origin
」を返す必要があります。
外部サービスからこのヘッダーが返されなかった場合、ブラウザはCORS仕様に従ってリクエストを停止し、上記のいずれかのエラーメッセージが表示されます。
以下の点を確認する
- 呼び出しの開始点となるURL(オリジン)は何か?このURLは、エラーメッセージに含まれている場合があります。
- 呼び出される外部サービスのURLは何か?このURLは、コンソールのエラーメッセージに含まれている場合があります。
- 取得される内容とその理由は何か?PNGファイルですか?スクリプト、CSS、またはフォントファイルですか?何が正確に取得され、何が使用されていますか?これにより、リモートアセットの詳しい用途と、そのアセットが重要である理由について把握することができます。
- この外部リソースの取得で認証は必要か?リダイレクトが必要な場合、応答ヘッダー「
Access-Control-Allow-Origin
」が返されない可能性があります。この場合、呼び出しが失敗します。リソースのURLを、ブラウザの新しいシークレットタブに直接コピーしてください。この方法は、通常の状況で外部リソースにアクセスできるかどうかをテストする場合に適しています(ただし、Webアプリのコード内でこの方法が機能するという保証はありません)。
- ブラウザの「ネットワーク」タブに「OPTIONS HTTP」メソッドの呼び出しが表示されているか?カスタムリクエストのヘッダーや認証などの条件がオリジン間リクエスト内に存在する場合、ブラウザによって追加のHTTP呼び出しが実行されます。これは、プリフライトコールともいいます。Webアプリのコードによってこの呼び出しが明示的に作成されることはありません。バックグラウンドで動作するブラウザにより、CORS仕様標準の一部としてこの呼び出しが作成されます。
このOPTIONS呼び出しが行われたとき、レスポンスが成功するため、リソースに対する実際のHTTP呼び出しが起こるために、特定の値がこの呼び出しの応答に含まれている必要があります。OPTIONS呼び出しが失敗した場合、リソースは取得されず、ブラウザのコンソールにCORSエラーが表示されます。
OPTIONS呼び出しが表示された場合は、その呼び出しをメモしてください。また、OPTIONS呼び出しの直前でリダイレクト(ステータス302)呼び出しが発生した場合も、その呼び出しをメモしてください。
OPTIONS呼び出しでリダイレクトが発生した場合、その呼び出しは高い確率で失敗します。この場合、リソースを取得するための呼び出しも失敗し、CORSエラーが発生します。
- どのような場合に外部リソースを取得するのか?この外部リソースを取得する理由を確認してください。これは、回避策や必要な変更の検討に重要である可能性があります。
- HARファイルを生成する:失敗したコールのスナップショットを取得し、その直前と直後に行われた処理を知ることで、問題をデバッグして、ユーザーが問題を再現できなくなるのを防ぐことができます。リクエストおよびレスポンス内のヘッダーを調べ、OPTIONSコールとリダイレクトを特定することができます。
次に考えられるステップ
- 外部サーバーの所有者はだれか?CORS仕様の標準に準拠して「
Access-Control-Allow-Origin
」ヘッダーを返すようにサーバーを変更できる可能性があります。ただし、サーバーが社内で管理されている場合であっても、この方法ですべてが解決されるわけではありません。ある特定の外部サービスがリソースを共有したくないという理由があるかもしれません。
外部サーバーが社内で何かしら管理されていない場合、ユースケースが有効であると仮定して、そのベンダーとやりとりしてみたり、別の回避策を検討してみてください。
- Zendesk App Frameworkを使用してアプリが作成されているか?client.request()呼び出しを使用して、バックエンドプロキシーバーを使用することができます。このプロキシーバーを使用するには、client.requestでcors:falseを設定します。この設定のデフォルト値は「false」です。プロキシサービスはバックエンドサービスであるため、ブラウザベースのCORS仕様に従う必要はありません。プロキシサービスを使用すると、オリジン間の呼び出しが成功する確率が高くなります。
ただし、プロキシサービスですべてが解決するわけではありません。プロキシサービスは、外部サービスからバイナリファイルやバイナリ情報を取得することはサポートしていません。他にアプリ固有の理由があるかもしれませんが、これもまた解決策ではありません。
- リソースを直接Webアプリに埋め込むことはできるか?オリジン間を移動してリソースを取得するのではなく、Webアプリにオリジンを含めることをお勧めします。これにより、オリジン間コールが完全に(ローカルリソースであるため)避けられ、CORSのどんな問題も消えてなくなります。ただし、これは必ずしも修正されているわけではありません。外部リソースURLがあらかじめわかっていないか、リソースが大きすぎてローカルリソースに収まらない場合や、リソースが頻繁に変更されてローカルの静的リソースとしてダウンロードされない場合があります。
- ブラウザのバージョンは何か?CORS仕様が標準であるにもかかわらず、ブラウザに表示されるメッセージが異なる場合があります。ChromeとFirefoxでは、異なるコンソールメッセージが表示されます。
- 修正できない場合があります。外部サービスからのリソースリクエストは、ブラウザWebアプリのコンテキストでは共有できない場合があります。リソース所有者が、リソースを共有するかどうかを判断します。これは、Webアプリの問題ではありません。仕様に従ってこうなっている場合がります。
詳細については、以下の記事を参照してください。
- Wikipediaの記事:クロスオリジンリソース共有
- Web.Devの記事:クロスオリジンリソース共有(CORS)
- Mozillaの記事:クロスオリジンリソース共有(CORS)
- Mozillaの記事:OPTIONS
- Fetchの記事:Fetch
- Fetchの記事:CORSプロトコル
0 コメント
サインインしてコメントを残してください。