1. セキュリティリスクとブラウザの制限
サーバー上のリソースが別のドメインにデプロイされている別のリソースを要求したり、別のポートを使用したりすると、前者のリソースはクロスオリジンHTTPリクエストを送信します。 たとえば、サイト http://www.aliyun.com のHTMLページは、URLが http://www.alibaba.com/image.jpg. である画像の要求を送信します。 インターネット上のほとんどのwebページでは、CSS、画像、スクリプトなどのリソースをさまざまなドメインから読み込むことができます。
セキュリティ上の理由から、ほとんどのブラウザはwebスクリプトからのクロスオリジンリクエストの送信を禁止しています。 他のブラウザでは、クロスオリジンリクエストを送信できますが、応答はブロックされます。 つまり、webアプリケーションがAPIを呼び出すと、同じドメイン内の関連リソースのみをロードできます。 別のドメインからリソースをロードするには、APIのクロスオリジンリソース共有 (CORS) を設定する必要があります。 このように、要求されたリソースが存在する宛先サーバは、クロスオリジン要求を承認する。

上の図は、クロスオリジンリソースアクセスの典型的なシナリオを示しています。 デフォルトでは、主流のブラウザはセキュリティ上の理由からクロスオリジンリソースアクセスを禁止しています。 ただし、これらのブラウザは、World Wide Web Consortium (W3C) が推奨するCORSメカニズムをサポートしています。 CORSメカニズムは、サーバおよびブラウザに基づいて実装される。 このメカニズムを使用すると、ブラウザでクロスオリジンリクエストを許可できるようになります。

2. CORS の概要
2.1 2つのリクエスト検証モード
CORSメカニズムは、2つの要求検証モードをサポートします。
クロスオリジンリクエストがすべて次の3つの条件を満たす場合、CORSメカニズムは単純なリクエスト検証を使用してクロスオリジンリクエストを処理します。
1. クロスオリジンリクエストは、次のいずれかの方法を使用します。
GET
HEAD
POST
2. クロスオリジンリクエストのContent-Typeヘッダーフィールドは、次のいずれかの値に設定されます。
application/x-www-form-urlencoded
multipart /フォームデータ
テキスト /プレーン
3. 以下のCORSヘッダーフィールドは、クロスオリジンリクエストのカスタムヘッダーフィールドを含め、Fetch標準で定義されています。
Accept
受け入れる-言語
Content-Language
Content-Type (このヘッダーフィールドは、2番目の条件に記載されている値のいずれかに設定する必要があります。)
DPR
ダウンリンク
保存-データ
ビューポート-幅
幅
クロスオリジン要求が上記のすべての条件を満たさない場合、CORSメカニズムは事前に割り当てられた要求検証を使用してクロスオリジン要求を処理します。
2.2 シンプルなリクエスト検証
シンプルリクエスト検証モードでは、ブラウザはクロスオリジンリクエストを送信します。 Originヘッダーフィールドはリクエストで指定され、リクエストがクロスオリジンリクエストであることを示します。 宛先サーバーがクロスオリジンリクエストを受信した後、サーバーは設定されたCORSルールに基づいてリクエストを許可するかどうかを判断します。 これに応答して、サーバーは、要求が許可されているかどうかを示すAccess-Control-Allow-OriginヘッダーとAccess-Control-Allow-Methodsヘッダーを返します。
前の図に示すように、成功応答にはAccess-Control-Allow-Originヘッダーフィールドが含まれています。 要約すると、単純リクエスト検証モードでは、ブラウザからのクロスオリジンリクエストにはoriginヘッダーフィールドが含まれている必要があり、ターゲットサーバーからの成功応答にはAccess-Control-Allow-Originヘッダーフィールドが含まれている必要があります。 この例では、成功応答のAccess-Control-Allow-Originヘッダーフィールドの値は * です。これは、要求されたリソースにすべてのドメインからアクセスできることを示します。 移行先サーバーがサイト http://www.aliyun.com からのクロスオリジンリクエストのみを許可する場合、次のコードスニペットに示すように、このヘッダーフィールドの値を http://www.aliyun.com として指定する必要があります。
Access-Control-Allow-Origin: http://www.aliyun.comこのようにして、サイト http://www.aliyun.com からのクロスオリジンリクエストのみが宛先サーバーによって許可されます。
2.3 優先リクエストの検証
優先要求検証モードでは、ブラウザがクロスオリジンリクエストを構築した後、クロスオリジンリクエストは宛先サーバーにすぐには送信されません。 代わりに、プリフライトされた要求が宛先サーバに送信される。 優先される要求は、HTTP OPTIONS要求である。 この要求は、要求されたリソースが存在する宛先サーバーが、現在のドメイン名からのクロスオリジンリクエストを許可するかどうかを確認するために使用されます。 移行先サーバーが現在のドメインからのクロスオリジンリクエストを許可している場合、ブラウザーは実際のクロスオリジンリクエストを送信します。
OPTIONS要求は、以下のヘッダ、すなわち、Origin、Access-Control-request-Method、およびAccess-Control-Request-headersを含む。 宛先サーバーがOPTIONS要求を受信した後、サーバーは、要求が許可されているかどうかを示すために、応答内のAccess-Control-Allow-Origin、Access-Control-Allow-Method、Access-Control-Allow-Headers、およびAccess-Control-Max-Ageヘッダーを指定します。 プリフライトリクエストが許可されている場合、ブラウザは実際のクロスオリジンリクエストを送信します。
OPTIONS要求内のAccess-Control-Request-Methodヘッダフィールドは、送信されるべきクロスオリジンリクエストがGETメソッドを使用することを宛先サーバに通知する。 OPTIONS要求内のAccess-Control-Request-Headersヘッダフィールドは、送信されるべきクロスオリジン要求が2つのカスタムヘッダフィールド: X-Ca-NonceおよびContent-Typeを含むことを宛先サーバに通知する。 OPTIONS要求内のこれら2つのヘッダフィールドに基づいて、宛先サーバは、クロスオリジン要求を許可するかどうかを決定する。
OPTIONSリクエストへの成功応答のAccess-Control-Allow-Methodsヘッダーフィールドは、ターゲットサーバーがブラウザからのクロスオリジンリクエストでGETメソッドを使用できるようにすることを示します。 複数のメソッドが許可されている場合、メソッドはコンマ (,) で区切られます。
OPTIONS要求に対する成功応答の中のAccess-Control-Allow-Headersヘッダフィールドは、宛先サーバが、クロスオリジン要求がX-Ca-NonceおよびContent-Typeヘッダフィールドを含むことを許可することを示す。 ヘッダーフィールドはコンマ (,) で区切られています。
OPTIONS要求に対する成功応答内のAccess-Control-Max-Ageヘッダフィールドは、応答が86,400秒間、すなわち24時間有効であることを示す。 この有効期間内に、ブラウザが同じクロスオリジンリクエストを再度送信する必要がある場合、ブラウザは別のプリフライトリクエストを送信する必要はありません。 ブラウザ自体がクロスオリジンリクエストの有効期間を指定することに注意してください。 Access-Control-Max-Ageヘッダーフィールドの値がブラウザで指定された有効期間を超えた場合、Access-Control-Max-Ageヘッダーフィールドは有効になりません。
3. API GatewayでのCORSメカニズムの実装
3.1 単純リクエスト検証モードの設定
デフォルトでは、API GatewayのすべてのAPIはクロスオリジンコールをサポートしています。 したがって、デフォルトでは、API GatewayはAccess-Control-Allow-Originヘッダーフィールドを追加し、各APIレスポンスでその値を * として指定します。 次のコードスニペットは、このプロセスの例を示しています。
クライアントからのAPIリクエスト
GET /simple HTTP/1.1
Host: www.alibaba.com
origin: http://www.aliyun.com
content-type: application/x-www-form-urlencoded; charset=utf-8
accept: application/json; charset=utf-8
date: Mon, 18 Sep 2017 09:53:23 GMT APIのバックエンドサービスからAPI Gatewayに送信されるレスポンス
HTTP/1.1 200 OK
Date: Mon, 18 Sep 2017 09:53:23 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 12
{"200","OK"} API Gatewayからクライアントに送信される応答
HTTP/1.1 200 OK
Date: Mon, 18 Sep 2017 09:53:23 GMT
Access-Control-Allow-Origin: *
X-Ca-Request-Id: 104735BD-8968-458F-9929-DBFA43F324C6
Content-Type: application/json; charset=UTF-8
Content-Length: 12
{"200","OK"} 上記のコードスニペットに示すように、API Gatewayは、バックエンドサービスから送信される応答に、次の情報を含む特定の情報を追加します。
Access-Control-Allow-Origin: * API Gatewayは、Access-Control-Allow-Originヘッダーフィールドを * として指定します。これは、APIをすべてのドメインから呼び出すことができることを示します。
Access-Control-Allow-Originヘッダーフィールドを別の値として指定する必要がある場合は、APIの応答情報を設定するときに、Access-Control-Allow-Originヘッダーフィールドを応答ヘッダーフィールドとして追加します。 Access-Control-Allow-Originヘッダーフィールドのカスタム値は、デフォルト値をオーバーライドします。 次のコードスニペットは、サイト http://www.aliyun.com からのみAPIを呼び出すことができる例を示しています。
クライアントからのAPIリクエスト
GET /simple HTTP/1.1
Host: www.alibaba.com
origin: http://www.aliyun.com
content-type: application/x-www-form-urlencoded; charset=utf-8
accept: application/json; charset=utf-8
date: Mon, 18 Sep 2017 09:53:23 GMT APIのバックエンドサービスからAPI Gatewayに送信されるレスポンス
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.aliyun.com
Date: Mon, 18 Sep 2017 09:53:23 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 12
{"200","OK"}API Gatewayからクライアントに送信される応答
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.aliyun.com
X-Ca-Request-Id: 104735BD-8968-458F-9929-DBFA43F324C6
Date: Mon, 18 Sep 2017 09:53:23 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 12
{"200","OK"}3.2 優先リクエスト検証モードの設定
API Gatewayでは、APIのHTTPリクエストメソッドをOPTIONSに設定できます。 このように、API Gatewayは、各OPTIONSリクエストをAPIのバックエンドサービスに直接渡します。 OPTIONSリクエストのみを許可するAPIを作成する場合は、次の項目に注意してください。
APIの基本情報を設定するときは、セキュリティ認証を認証なしに設定します。
APIのリクエスト情報を設定するときは、[リクエストパス] フィールドに /を入力し、[すべてのサブパスに一致する] チェックボックスをオンにします。 HTTPメソッドをOPTIONSに設定すると、リクエストモードパラメーターは自動的にパススルーに設定され、変更できません。 API操作のリクエストパラメーターを定義する必要はありません。
APIグループごとに、OPTIONSリクエストのみを許可するAPIを作成し、このAPIを使用してAPIグループのCORSポリシーを設定できます。 curlを使用して、OPTIONSリクエストのみを許可するAPIのHTTPリクエストをテストできます。 次のコードスニペットは、curlを使用してAPIを呼び出す例を示しています。
sudo curl -X OPTIONS -H "Access-Control-Request-Method:POST" -H "Access-Control-Request-Headers:X-CUSTOM-HEADER" http://ec12ac094e734544be02c928366b7b26-cn-qingdao.alicloudapi.com/optinstest -i
HTTP/1.1 200 OK
Server: Tengine
Date: Sun, 02 Sep 2018 15:32:19 GMT
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,HEAD,OPTIONS,PATCH
Access-Control-Allow-Headers: X-CUSTOM-HEADER
Access-Control-Max-Age: 172800
X-Ca-Request-Id: 1016AC86-E345-405C-8049-A6C24078F65F
OPTIONSリクエストのみを許可するAPI操作を設定する場合、API GatewayはAPI操作のバックエンドサービスからの各応答に4つのヘッダーフィールドを追加することに注意してください: Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers、およびAccess-Control-Max-Age。 したがって、4つのヘッダーフィールドをAPI操作のレスポンスヘッダーフィールドとして追加し、必要に応じて値を指定して、カスタム値がデフォルト値を上書きするようにする必要があります。
次のコードスニペットは、優先的なリクエスト検証モードでのクロスオリジンAPI呼び出しの例を示しています。
クライアントからのOPTIONSリクエスト
OPTIONS /simple HTTP/1.1
Host: www.alibaba.com
origin: http://www.aliyun.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
accept: application/json; charset=utf-8
date: Mon, 18 Sep 2017 09:53:23 GMTAPIのバックエンドサービスからAPI Gatewayに送信されるレスポンス
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.aliyun.com
Access-Control-Allow-Methods: GET,POST
Access-Control-Allow-Headers: X-CUSTOM-HEADER
Access-Control-Max-Age: 10000
Date: Mon, 18 Sep 2017 09:53:23 GMT
Content-Type: application/json; charset=UTF-8API Gatewayからクライアントに送信される応答
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.aliyun.com
Access-Control-Allow-Methods: GET,POST
Access-Control-Allow-Headers: X-CUSTOM-HEADER
Access-Control-Max-Age: 10000
X-Ca-Request-Id: 104735BD-8968-458F-9929-DBFA43F324C6
Date: Mon, 18 Sep 2017 09:53:23 GMT
Content-Type: application/json; charset=UTF-8クライアントからのクロスオリジンAPIリクエスト
GET /simple HTTP/1.1
Host: www.alibaba.com
origin: http://www.aliyun.com
content-type: application/x-www-form-urlencoded; charset=utf-8
accept: application/json; charset=utf-8
date: Mon, 18 Sep 2017 09:53:23 GMTAPIのバックエンドサービスからAPI Gatewayに送信されるレスポンス
HTTP/1.1 200 OK
Date: Mon, 18 Sep 2017 09:53:23 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 12
{"200","OK"}API Gatewayからクライアントに送信される応答
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,HEAD,OPTIONS,PATCH
Access-Control-Allow-Headers: X-Requested-With,X-Sequence,X-Ca-Key,X-Ca-Secret,X-Ca-Version,X-Ca-Timestamp,X-Ca-Nonce,X-Ca-API-Key,X-Ca-Stage,X-Ca-Client-DeviceId,X-Ca-Client-AppId,X-Ca-Signature,X-Ca-Signature-Headers,X-Forwarded-For,X-Ca-Date,X-Ca-Request-Mode,Authorization,Content-Type,Accept,Accept-Ranges,Cache-Control,Range,Content-MD5
Access-Control-Max-Age: 172800
X-Ca-Request-Id: 104735BD-8968-458F-9929-DBFA43F324C6
Date: Mon, 18 Sep 2017 09:53:23 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 12
{"200","OK"}