Send Docs Feedback

Note: Most user interface tasks can be performed in Edge Classic or the New Edge experience. For an overview, getting started topics, and release notes specific to the New Edge experience, see the docs.

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

CORS (クロスオリジンリソース共有) は、Web ページで実行される JavaScript XMLHttpRequest (XHR) 呼び出しが非オリジンドメインのリソースとやり取りできるようにする、標準メカニズムです。CORS は、あらゆるブラウザで強制されている「同一オリジンポリシー」に対して一般的に実装されている対策です。例えば、ブラウザで実行中の JavaScript コードから Twitter API へという XHR 呼び出しは失敗します。その理由は、ブラウザに該当ページをサービスしているドメインが、Twitter API をサービスしているドメインと同じでないからです。CORS はこの問題を解消すべく、サーバーがクロスオリジンでリソースを共有したい場合に、サーバーが「オプトイン」できる (承諾を得られる) ようにします。 

最近のブラウザはほとんどが CORS 対応です。対応ブラウザの一覧については、こちらを参照してください。CORS の詳細な説明については、「Cross-Origin Resource Sharing W3C Recommendation」を参照してください。

API プロキシ上でキャッシュポリシーを使用する場合は、CORS ポリシーのレスポンスがキャッシュされないようにする必要があります。

一般的な CORS 使用例

The following JQuery code calls a fictitious target service. If executed from within the context of a browser (a web page), the call will fail because of the same-origin policy:

<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>

One solution to this problem is to create an Apigee API proxy that calls the service API on the back end. Remember that Edge sits between the client (a browser in this case) and the backend API (the service). Because the API proxy executes on the server, not in a browser, it is able to call the service successfully. Then, all you need to do is attach CORS headers to the TargetEndpoint response. As long as the browser supports CORS, these headers signal to the browser that it's okay to "relax" its same-origin policy, allowing the cross-origin API call to succeed.

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>

最もシンプルなケースでは、CORS ヘッダーをクライアントに返せばクロスオリジンリクエストは機能します。「プリフライト」リクエストが必要となるような、より複雑なケースもあります。プリフライト CORS リクエストについては、「Cross-Origin Resource Sharing W3C Recommendation」や数多くの記事やブログを参考にできます。後述の「CORS プリフライトリクエストの処理」も参照してください。

新しい API プロキシへの Add CORS ポリシーの添付 

「Add CORS」ポリシーを作成時に API プロキシに添付することで、API プロキシに CORS サポートを追加できます。このポリシーを追加するには、「Build a Proxy」ウィザードの「Security」ページで「Add CORS headers」チェックボックスを選択します。 

このチェックボックスをオンにすると、以下の図に示すように、自動的に Add CORS というポリシーがシステムに追加され、TargetEndpoint レスポンスプレフローに添付されます。

Add CORS ポリシーは AssignMessage ポリシーとして実装されます。このポリシーが、適切なヘッダーをレスポンスに追加します。Add CORS ポリシーのための XML を以下に示します。

<AssignMessage async="false" continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <FaultRules/>
    <Properties/>
    <Add>
        <Headers>
            <Header name="Access-Control-Allow-Origin">{request.header.origin}</Header>
            <Header name="Access-Control-Allow-Headers">origin, x-requested-with, accept, content-type</Header>
            <Header name="Access-Control-Max-Age">3628800</Header>
            <Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE</Header>
        </Headers>
    </Add>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

Basically, the headers let the browser know which origins it will share its resources with, which methods it accepts, and so on. You can read more about these CORS headers in the Cross-Origin Resource Sharing W3C Recommendation.

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

You need to manually create a new Assign Message policy and copy the code for the Add CORS policy listed in the previous section into it. Then, attach the policy to the response preflow of the TargetEndpoint of the API proxy. You can modify the header values as needed. For more information on creating and attaching policies, see What's a policy?.

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

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

通常、CORS プリフライトリクエストは、HTTP OPTIONS メソッドによって行われます。CORS をサポートしているサーバーが OPTIONS リクエストを受信すると、そのサーバーの CORS サポートレベルを示す CORS ヘッダーのセットをクライアントに返します。このハンドシェイクの結果、クライアントは、非オリジンドメインからリクエストすることを許可されている内容を理解します。 

プリフライトの詳細については、「Cross-Origin Resource Sharing W3C Recommendation」を参照してください。CORS については、参考になるブログや記事が他にも多数あります。

CORS プリフライトソリューションは、Apigee には含まれませんが、このセクションの説明に従って実装することは可能です。目標は、プロキシが条件フローで OPTIONS リクエストを評価することです。そうすれば、プロキシが、適切なレスポンスをクライアントに返信できます。 

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

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request/>
            <Response>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </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.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 では以下の部分が重要です。

  • A RouteRule is created to a NULL target with a condition for the OPTIONS request. Note that there is no TargetEndpoint specified. If the OPTIONS request is received and the Origin and Access-Control-Request-Method request headers are not null, the proxy immediately returns the CORS headers in a response to the client (bypassing the actual default "backend" target).  For details on flow conditions and RouteRule, see Flow variables and conditions.

    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    
  • An OptionsPreFlight flow is created that adds an Add CORS policy, containing the CORS headers, to the flow if an OPTIONS request is received and the Origin and Access-Control-Request-Method request headers are not null. 

     <Flow name="OptionsPreFlight">
                <Request/>
                <Response>
                    <Step>
                        <Name>add-cors</Name>
                    </Step>
                </Response>
            <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition> 
     </Flow>

RouteRules は、ProxyEndpoint 構成に指定されている順序で評価されます。デフォルト (条件なし) の Route は必ず末尾に指定してください。そうではなく、先頭にあった場合、必ず一致して他の Route の可能性が一切評価されなくなります。

Help or comments?