API プロキシへの CORS サポートの追加

このページの内容は ApigeeApigee ハイブリッドに該当します。

Apigee Edge のドキュメントを表示する。

CORS(クロスオリジン リソース シェアリング)は、ウェブページで実行される JavaScript XMLHttpRequest(XHR)呼び出しがオリジン以外のドメインのリソースとやり取りできるようにする標準的なメカニズムです。CORS は、すべてのブラウザに組み込まれている同一オリジン ポリシーに対する一般的な解決策です。たとえば、ブラウザで実行されている JavaScript コードから Twitter API への XHR 呼び出しは失敗します。これは、ブラウザに該当ページを提供しているドメインが、Twitter API を提供しているドメインと異なるためです。CORS は、この制約を解消するための手段です。サーバーが異なるオリジンのリソースを共有したい場合に、サーバーがアクセスをオプトイン(承諾)できるようにします。

CORS の一般的な使用例

次の JQuery コードは架空のターゲット サービスを呼び出します。この呼び出しをブラウザ(ウェブページ)のコンテキストから実行すると、同一オリジン ポリシーにより呼び出しが失敗します。

<script>
var url = "http://service.example.com";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This is where we end up!
            }
    });
  });
});
</script>

この制約を回避する一つの方法として、バックエンドでサービス API を呼び出す Apigee API プロキシを作成する方法があります。Apigee はクライアント(この場合はブラウザ)とバックエンド API(サービス)の間に存在します。API プロキシはブラウザではなくサーバー上で実行されるため、サービスを正常に呼び出すことができます。この場合、必要な作業は TargetEndpoint レスポンスに CORS ヘッダーを追加することだけです。ブラウザで CORS がサポートされていれば、これらのヘッダーにより、ブラウザは同一オリジン ポリシーを「緩和」しても問題ないことを認識し、クロスオリジン API 呼び出しが正常に動作するようになります。

CORS をサポートするプロキシを作成したら、クライアント側のコードでバックエンド サービスではなく API プロキシ URL を呼び出すことができます。次に例を示します。

<script>
var url = "http://myorg-test.apigee.net/v1/example";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This time, we do not end up here!
            }
    });
  });
});
</script>

ProxyEndpoint のリクエスト PreFlow への CORS ポリシーの接続

新しい API プロキシへの Add CORS ポリシーの接続

API プロキシに CORS サポートを追加するには、次の方法で Add CORS ポリシーを API プロキシに適用します。

  • [Build a Proxy] ウィザードの [Security] ページで [Add CORS headers] チェックボックスをオンにしてポリシーを作成する
  • [Add Policy] ダイアログで後で追加する

チェックボックスをオンにして CORS ポリシーを追加すると、「Add CORS」というポリシーが自動的に追加され、TargetEndpoint リクエスト PreFlow に接続します。

Add CORS ポリシーは、レスポンスに適切なヘッダーを追加します。これらのヘッダーにより、リソースを共有するオリジンや許可するメソッドなどをブラウザに知らせることができます。CORS ヘッダーの詳細については、クロスオリジン リソース シェアリングの W3C 勧告をご覧ください。

次のようにポリシーを変更する必要があります。

  • このコードの抜粋のように、content-typeauthorization ヘッダー(基本認証または OAuth2 のサポートに必要)を Access-Control-Allow-Headers ヘッダーに追加します。
  • OAuth2 認証の場合は、RFC を遵守していない動作を修正する必要があります。
<CORS continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <AllowOrigins>{request.header.origin}</AllowOrigins>
    <AllowMethods>GET, PUT, POST, DELETE</AllowMethods>
    <AllowHeaders>origin, x-requested-with, accept, content-type, authorization</AllowHeaders>
    <ExposeHeaders>*</ExposeHeaders>
    <MaxAge>3628800</MaxAge>
    <AllowCredentials>false</AllowCredentials>
    <GeneratePreflightResponse>true</GeneratePreflightResponse>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</CORS>

既存のプロキシへの CORS ヘッダーの追加

新しいプロキシ エディタ

既存の API プロキシに CORS ポリシーを追加するには:

  1. Google Cloud コンソールの Apigee UI を使用している場合: [プロキシ開発] > [API プロキシ] を選択します。

    従来の Apigee UI を使用している場合: [開発] > [API プロキシ] を選択して、[プロキシ] ペインでプロキシの環境を選択します。

  2. CORS ポリシーを追加する API プロキシを選択します。
  3. 新しい API プロキシ エディタで、[開発] タブをクリックします。
  4. 左側のパネルで、[ポリシー] 行の [+] ボタンをクリックします。
  5. [ポリシーの作成] ダイアログで、[Select policy type] フィールドをクリックし、[セキュリティ] まで下にスクロールして、[CORS] を選択します。

  6. ポリシーの詳細を入力し、[作成] をクリックします。

  7. 左側のペインで、[ターゲット エンドポイント] > [デフォルト] の下にある [PreFlow] をクリックします。
  8. ビジュアル エディタの右下にある [リクエスト] ペインの [PreFlow] の横にある [+] ボタンをクリックします。
  9. [Add policy step] ダイアログで、[CORS] ポリシーを選択します。
  10. [追加] をクリックしてポリシーを適用します。

従来のプロキシ エディタ

既存の API プロキシに CORS ポリシーを追加するには:

  1. Apigee UI にログインします。
  2. 左側のナビゲーション バーで [Develop] > [API Proxies] を選択します。
  3. [今すぐ試す] ボタンが表示されている場合は、クリックして新しい [Develop] ビューを表示します。

    [開発] ビューを以下に示します。

    プロキシ エディタの [開発] ビュー

  4. CORS ポリシーを追加する API プロキシを選択します。
  5. 新しい API プロキシ エディタで、[開発] タブをクリックします。
  6. 左側のナビゲータ ペインで、[ターゲット エンドポイント] > [デフォルト] の下にある [PreFlow] をクリックします。
  7. リクエストの PreFlow に対応する最上部の [+ ステップ] ボタンをクリックします。これにより、作成可能なポリシーの一覧がカテゴリ別に表示されます。
  8. [セキュリティ] カテゴリで [CORS] を選択します。
  9. Add CORS などの名前を指定して、[追加] をクリックします。

CORS プリフライト リクエストの処理

CORS プリフライトとは、サーバーにリクエストを送信して相手が CORS に対応しているかどうかを確認することです。一般的なプリフライト レスポンスには、サーバーが CORS リクエストを受け入れるオリジン、CORS リクエストでサポートされている HTTP メソッドの一覧、リソース リクエストの一部として使用できるヘッダー、プリフライト リクエストがキャッシュに保存される最長時間などが含まれます。サービスが CORS をサポートしていない場合や、クライアントのオリジンからのクロスオリジン リクエストを承諾していない場合、ブラウザのクロスオリジン ポリシーが適用され、サーバーにホストされているリソースとやり取りするためにクライアントから送信されたクロスドメイン リクエストは失敗します。

通常、CORS プリフライト リクエストは HTTP OPTIONS メソッドによって行われます。CORS をサポートしているサーバーが OPTIONS リクエストを受信すると、CORS サポートのレベルを示す一連の CORS ヘッダーをクライアントに返します。この handshake の結果、クライアントは、オリジン以外のドメインからリクエストできる内容を認識します。

プリフライトの詳細については、クロスオリジン リソース シェアリングの W3C 勧告をご覧ください。CORS については、参考になるブログや記事が他にも多数あります。

Apigee には、すぐに使用できる CORS プリフライト ソリューションは用意されていませんが、このセクションの説明に従って実装できます。プロキシが条件付きフローで OPTIONS リクエストを評価できるようにすることで、プロキシは適切なレスポンスをクライアントに返すことができます。

まず、サンプルのフローを示します。その後に、プリフライト リクエストを処理する各部分について説明します。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </Request>
            <Response/>
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
        </Flow>
    </Flows>

    <PreFlow name="PreFlow">
        <Request/>
        <Response/>

    </PreFlow>
    <HTTPProxyConnection>
        <BasePath>/v1/cnc</BasePath>
        <VirtualHost>default</VirtualHost>
        <VirtualHost>secure</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
   </RouteRule>
   <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
</ProxyEndpoint>

この ProxyEndpoint では重要な部分は次のとおりです。

  • RouteRule は、OPTIONS リクエストの条件が指定されている NULL ターゲットに作成されます。TargetEndpoint が指定されていないことに注意してください。OPTIONS リクエストを受信し、Origin と Access-Control-Request-Method リクエスト ヘッダーが null でない場合、クライアントへのレスポンスでプロキシはすぐに(デフォルトのバックエンド ターゲットをバイパスして)CORS ヘッダーを返します。フロー条件と RouteRule の詳細については、フロー変数での条件をご覧ください。
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
  • OPTIONS リクエストを受信し、Origin と Access-Control-Request-Method リクエスト ヘッダーが null でない場合、CORS ヘッダーのほかに、Add CORS ポリシーをフローに追加する OptionsPreFlight フローが作成されます。
     <Flow name="OptionsPreFlight">
                <Request>
                    <Step>
                        <Name>add-cors</Name>
                    </Step>
                </Request>
                <Response/>
            <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
     </Flow>