CORS通信
CORS は W3C の標準であり、正式名称は「Cross-origin resource Sharing」(クロスオリジン リソース シェアリング)、通称「クロスオリジン リソース シェアリング」と呼ばれています。これにより、ブラウザーがクロスオリジン サーバーに「XMLHttpRequest」リクエストを発行できるようになり、AJAX は同じオリジンからのみ使用できるという制限が克服されます。
導入
CORS にはブラウザとサーバーの両方のサポートが必要です。現在、すべてのブラウザがこの機能をサポートしています。
CORS 通信プロセス全体はブラウザによって自動的に完了し、ユーザーの参加は必要ありません。開発者にとって、CORS 通信は通常の AJAX 通信と何ら変わりはなく、コードもまったく同じです。ブラウザーが AJAX リクエストがクロスオリジンであることを検出すると、追加のヘッダー情報が自動的に追加され、場合によっては追加のリクエストが行われることもありますが、ユーザーはそれに気づきません。したがって、CORS 通信を実現する鍵となるのはサーバーです。サーバーが CORS インターフェイスを実装している限り、クロスオリジン通信が可能です。
2 つのリクエスト
CORS リクエストは、単純なリクエストとそれほど単純ではないリクエストの 2 つのカテゴリに分類されます。
以下の2つの条件を同時に満たしていれば簡単なリクエストです。
(1) リクエスト方法は以下の3つの方法のいずれかです。
-頭 -GET
- 投稿
(2) HTTP ヘッダ情報は以下のフィールドを超えない。
-受け入れる
- 言語の受け入れ
- コンテンツ言語 -最終イベントID
- Content-Type:
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
の 3 つの値に制限されます
上記 2 つの条件を同時に満たさないリクエストは、非単純リクエストです。一言で言えば、単純なリクエストは、単純な HTTP メソッドと単純な HTTP ヘッダーの組み合わせです。
この分割の理由は、歴史的にフォームは起源を越えてリクエストを行うことができたためです。単純なリクエストはフォームリクエストです。ブラウザは従来の処理方法に従い、動作を複雑にしません。それ以外の場合、開発者は CORS 制限を回避するためにフォームの使用に切り替えることができます。単純でないリクエストの場合、ブラウザは新しい処理方法を採用します。
簡単なリクエスト
基本的なプロセス
単純なリクエストの場合、ブラウザは CORS リクエストを直接作成します。具体的には、ヘッダ情報に「Origin」フィールドを追加することである。
以下は例です。ブラウザは、このクロスオリジン AJAX リクエストが単純なリクエストであることを認識し、ヘッダー情報に「Origin」フィールドを自動的に追加します。
GET /cors HTTP/1.1
起源: http://api.bob.com
ホスト: api.alice.com
受け入れ言語: en-US
接続: キープアライブ
ユーザーエージェント: Mozilla/5.0...
上記のヘッダー情報では、「Origin」フィールドを使用して、このリクエストがどのドメインから送信されているかを示します (プロトコル + ドメイン名 + ポート)。サーバーは、この値に基づいてリクエストに同意するかどうかを決定します。
Origin
で指定されたオリジンが許可範囲内にない場合、サーバーは通常の HTTP 応答を返します。ブラウザは、この応答のヘッダー情報に「Access-Control-Allow-Origin」フィールド (詳細は以下を参照) が含まれていないことを検出すると、何か問題が発生したことを認識し、エラーをスローします。これは、「onerror」によって捕捉されます。 XMLHttpRequest
のコールバック関数。 HTTP 応答のステータス コードが 200 である可能性があるため、このエラーはステータス コードでは特定できないことに注意してください。
「Origin」で指定されたドメイン名が許可範囲内にある場合、サーバーから返される応答にはさらにいくつかのヘッダー情報フィールドが含まれます。
アクセス制御許可オリジン: http://api.bob.com
アクセス制御許可資格情報: true
アクセス制御公開ヘッダー: FooBar
コンテンツタイプ: 文字セット=utf-8;
上記のヘッダー情報の中には、CORS リクエストに関連する 3 つのフィールドがあり、すべて Access-Control-
で始まります。
(1)アクセス制御許可オリジン
この項目は必須です。その値は、リクエストの「Origin」フィールドの値、または任意のドメイン名からのリクエストが受け入れられることを示す「*」のいずれかです。
(2)「アクセス制御許可認証情報」
このフィールドはオプションです。その値は、Cookie の送信が許可されているかどうかを示すブール値です。デフォルトでは、Cookie は CORS リクエストに含まれません。 「true」に設定すると、サーバーは、ブラウザーがリクエストに Cookie を含めてサーバーに送信することを明示的に許可します。この値は「true」にのみ設定できます。サーバーがブラウザーに Cookie を送信させたくない場合は、このフィールドを送信しないでください。
(3)「アクセス制御公開ヘッダー」
このフィールドはオプションです。 CORS リクエストを作成する場合、XMLHttpRequest
オブジェクトの getResponseHeader()
メソッドは、サーバーから返される 6 つの基本フィールドのみを取得できます: Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、プラグマ
。他のフィールドを取得したい場合は、「Access-Control-Expose-Headers」で指定する必要があります。上の例では、getResponseHeader('FooBar')
が FooBar
フィールドの値を返すことができることを指定しています。
withCredentials 属性
前述したように、CORS リクエストにはデフォルトで Cookie 情報 (および HTTP 認証情報など) が含まれません。これは、CSRF 攻撃のリスクを軽減するためです。ただし、場合によっては、サーバーが Cookie を取得する必要がある場合があります。この場合、サーバーは「Access-Control-Allow-Credentials」フィールドを明示的に指定して、Cookie を送信できることをブラウザーに伝える必要があります。
アクセス制御許可資格情報: true
同時に、開発者は AJAX リクエストの withCredentials
属性をオンにする必要があります。
var xhr = 新しい XMLHttpRequest();
xhr.withCredentials = true;
そうしないと、サーバーが Cookie の送信を要求しても、ブラウザは Cookie を送信しません。または、サーバーが Cookie の設定を要求しても、ブラウザはそれを処理しません。
ただし、一部のブラウザでは、デフォルトで「withCredentials」属性が「true」に設定されます。これは、「withCredentials」設定が省略された場合でも、これらのブラウザーは依然として Cookie を一緒に送信する可能性があることを意味します。現時点では、「withCredentials」を明示的にオフにすることができます。
xhr.withCredentials = false;
サーバーがブラウザに Cookie の送信を要求する場合、「Access-Control-Allow-Origin」をアスタリスクに設定することはできず、要求された Web ページと一致する明確なドメイン名を指定する必要があることに注意してください。同時に、Cookie は同一オリジン ポリシーに従います。サーバー ドメイン名で設定された Cookie のみがアップロードされ、(クロスオリジン) の document.cookie
はアップロードされません。元の Web ページのコードはサーバーのドメイン名を読み取ることができません。
単純ではないリクエスト
プリフライトリクエスト
非単純リクエストとは、リクエストメソッドが「PUT」または「DELETE」である、または「Content-Type」フィールドのタイプが「application/json」であるなど、サーバーに特別な要件を課すリクエストです。
単純なリクエストではない CORS リクエストは、正式な通信の前に「プリフライト」リクエストと呼ばれる HTTP クエリ リクエストを追加します。ブラウザはまずサーバーに、現在の Web ページのドメイン名がサーバーの許可リストに含まれているかどうか、またどの HTTP メソッドとヘッダー フィールドを使用できるかを尋ねます。肯定的な応答を受信した場合にのみ、ブラウザは正式な XMLHttpRequest
リクエストを発行します。そうでない場合は、エラーが報告されます。これは、これらの新しいリクエストが CORS サポートのない従来のサーバーに負荷をかけるのを防ぎ、サーバーが大量の「DELETE」リクエストと「PUT」リクエストを受信するのを事前に防ぐためです。従来の形式では、オリジンを越えて行われるリクエストはできません。
以下はブラウザの JavaScript スクリプトです。
var url = 'http://api.alice.com/cors';
var xhr = 新しい XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-カスタムヘッダー', '値');
xhr.send();
上記のコードでは、HTTP リクエスト メソッドは PUT
で、カスタム ヘッダー情報 X-Custom-Header
が送信されます。
ブラウザは、これが単純ではないリクエストであることを認識し、「プリフライト」リクエストを自動的に発行し、そのようなリクエストを実行できるかどうかをサーバーに確認します。以下は、この「プリフライト」リクエストの HTTP ヘッダーです。
オプション /cors HTTP/1.1
起源: http://api.bob.com
アクセス制御要求メソッド: PUT
アクセス制御リクエストヘッダー: X-カスタムヘッダー
ホスト: api.alice.com
受け入れ言語: en-US
接続: キープアライブ
ユーザーエージェント: Mozilla/5.0...
「プリフライト」リクエストに使用されるリクエストメソッドは「OPTIONS」であり、このリクエストが問い合わせであることを示します。ヘッダー情報のキー フィールドは「Origin」で、リクエストの送信元を示します。
「Origin」フィールドに加えて、「プリフライト」リクエストのヘッダー情報には 2 つの特別なフィールドが含まれます。
(1)「アクセス制御リクエスト方法」
このフィールドは必須であり、ブラウザの CORS リクエストで使用される HTTP メソッドをリストするために使用されます。上の例は「PUT」です。
(2)「アクセス制御リクエストヘッダー」
このフィールドは、ブラウザが CORS リクエストで送信する追加のヘッダー フィールドを指定するカンマ区切りの文字列です。上の例は「X-Custom-Header」です。
プリフライトリクエストへの応答
サーバーは「プリフライト」リクエストを受信すると、「Origin」、「Access-Control-Request-Method」、および「Access-Control-Request-Headers」フィールドをチェックし、クロスオリジンリクエストが許可されていることを確認し、応答できることを確認します。 。
HTTP/1.1 200 OK
日付: 2008 年 12 月 1 日月曜日 01:15:39 GMT
サーバー: Apache/2.0.61 (Unix)
アクセス制御許可オリジン: http://api.bob.com
アクセス制御許可メソッド: GET、POST、PUT
アクセス制御許可ヘッダー: X-カスタムヘッダー
コンテンツタイプ: 文字セット=utf-8;
コンテンツエンコーディング: gzip
コンテンツの長さ: 0
キープアライブ: タイムアウト = 2、最大 = 100
接続: キープアライブ
上記の HTTP 応答では、キーは「Access-Control-Allow-Origin」フィールドです。これは、「http://api.bob.com」がデータをリクエストできることを意味します。このフィールドをアスタリスクに設定して、クロスオリジン要求に同意することもできます。
アクセス制御許可オリジン: *
サーバーが「プリフライト」リクエストを拒否した場合、通常の HTTP 応答が返されますが、CORS 関連のヘッダー フィールドは含まれないか、リクエストが条件を満たしていないことを明示的に示しません。
オプション http://api.bob.com HTTP/1.1
ステータス: 200
アクセス制御許可オリジン: https://notyourdomain.com
アクセス制御許可メソッド: POST
上記のサーバー応答の「Access-Control-Allow-Origin」フィールドには、リクエストの送信元である「http://api.bob.com」が明示的に含まれていません。
この時点で、ブラウザはサーバーがプリフライト リクエストに同意しないと判断し、エラーをトリガーします。このエラーは、XMLHttpRequest
オブジェクトの onerror
コールバック関数によってキャッチされます。コンソールには次のエラー メッセージが出力されます。
XMLHttpRequest は http://api.alice.com をロードできません。
オリジン http://api.bob.com は、Access-Control-Allow-Origin によって許可されていません。
サーバー応答内のその他の CORS 関連フィールドは次のとおりです。
アクセス制御許可メソッド: GET、POST、PUT
アクセス制御許可ヘッダー: X-カスタムヘッダー
アクセス制御許可資格情報: true
アクセス制御の最大有効期間: 1728000
(1)「アクセス制御の許可メソッド」
このフィールドは必須であり、その値はサーバーでサポートされているすべてのクロスオリジン要求メソッドを示すカンマ区切りの文字列です。ブラウザによって要求されたメソッドだけでなく、サポートされているすべてのメソッドが返されることに注意してください。これは、複数の「プリフライト」リクエストを回避するためです。
(2)「アクセス制御許可ヘッダー」
ブラウザリクエストに「Access-Control-Request-Headers」フィールドが含まれる場合、「Access-Control-Allow-Headers」フィールドは必須です。これは、「プリフライト」でブラウザによって要求されたフィールドに限定されず、サーバーによってサポートされるすべてのヘッダー フィールドを示すカンマ区切りの文字列でもあります。
(3)「アクセス制御許可認証情報」
このフィールドは、単純なリクエストの場合と同じ意味を持ちます。
(4)「アクセス制御の最大有効期間」
このフィールドはオプションであり、このプリフライト要求の有効期間を秒単位で指定するために使用されます。上記の結果では、有効期間は 20 日 (1728000 秒) です。これは、応答を 1728000 秒 (20 日間) キャッシュできることを意味します。この期間中は、別のプリフライト リクエストを発行する必要はありません。
通常のブラウザからのリクエストとレスポンス
サーバーが「プリフライト」リクエストを渡すと、ブラウザからの後続のすべての通常の CORS リクエストは、「Origin」ヘッダー フィールドを持つ単純なリクエストと同じになります。サーバーの応答には「Access-Control-Allow-Origin」ヘッダー フィールドも含まれます。
以下は、「プリフライト」リクエスト後のブラウザからの通常の CORS リクエストです。
PUT /cors HTTP/1.1
起源: http://api.bob.com
ホスト: api.alice.com
X-カスタムヘッダー: 値
受け入れ言語: en-US
接続: キープアライブ
ユーザーエージェント: Mozilla/5.0...
上記のヘッダー情報の「Origin」フィールドは、ブラウザによって自動的に追加されます。
以下はサーバーからの通常の応答です。
アクセス制御許可オリジン: http://api.bob.com
コンテンツタイプ: 文字セット=utf-8;
上記のヘッダー情報では、「Access-Control-Allow-Origin」フィールドがすべての応答に含まれている必要があります。
JSONPとの比較
CORS は JSONP と同じ目的で使用されますが、JSONP よりも強力です。 JSONP は「GET」リクエストのみをサポートしますが、CORS はすべてのタイプの HTTP リクエストをサポートします。 JSONP の利点は、古いブラウザーのサポートと、CORS をサポートしていない Web サイトからデータを要求できることです。
参考リンク
- CORS の使用、Monsur Hossain
- HTTP アクセス制御 (CORS)、MDN
- CORS、ライアン・ミラー
- CORS を本当に知っていますか?、Grzegorz Mirek
作者: wangdoc
アドレス: https://wangdoc.com/
ライセンス: クリエイティブ・コモンズ 3.0