為 API Proxy 新增 CORS 支援

本頁內容適用於 ApigeeApigee Hybrid

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

解決這個問題的方法之一,是建立 Apigee API Proxy,在後端呼叫服務 API。請注意,Apigee 位於用戶端 (本例中為瀏覽器) 和後端 API (服務) 之間。由於 API Proxy 是在伺服器上執行,而非在瀏覽器中,因此能夠順利呼叫服務。接著,您只需要將 CORS 標頭附加至 TargetEndpoint 回應即可。只要瀏覽器支援 CORS,這些標頭就會向瀏覽器發出信號,表示可以放寬同源政策,允許跨源 API 呼叫成功。

建立支援 CORS 的 Proxy 後,您可以在用戶端程式碼中呼叫 API Proxy 網址,而非後端服務。例如:

<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 政策附加至 ProxyEndpoint 的要求 PreFlow

將「新增 CORS」政策附加至新的 API Proxy

如要為 API Proxy 新增 CORS 支援,請將「Add CORS」政策附加至 API Proxy。

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

在現有 Proxy 中新增 CORS 標頭

如要將 CORS 政策新增至現有 API Proxy,請按照下列步驟操作:

  1. 在 Google Cloud 控制台中,前往「Proxy 開發」>「API Proxy」頁面。

    前往「API Proxies」(API Proxy)

  2. 選取要新增 CORS 政策的 API Proxy。使用者介面會在 Google Cloud 控制台中顯示 Proxy 詳細資料。
  3. 點選「Develop」分頁標籤。
  4. 在導覽窗格中,按一下「Policies」列的「+」按鈕。
  5. 在「建立政策」對話方塊中,按一下「選取政策」欄位,然後向下捲動至「安全性」,並選取「CORS」

  6. 輸入政策詳細資料,然後按一下「建立」

  7. 在導覽窗格中,依序點選「Target Endpoints」>「default」下方的「PreFlow」
  8. 在 Visual Editor 的「Request」窗格中,點選「PreFlow」旁的「+」按鈕。
  9. 在「Add policy step」對話方塊中,選取「CORS」CORS政策。
  10. 按一下「新增」即可附加政策。

處理 CORS 預檢要求

CORS 預檢是指將要求傳送至伺服器,確認伺服器是否支援 CORS。典型的預檢回應包括伺服器會接受哪些來源的 CORS 要求、CORS 要求支援的 HTTP 方法清單、可用於資源要求中的標頭、預檢回應的快取時間上限等。如果服務未指出支援 CORS,或不希望接受來自用戶端來源的跨源要求,瀏覽器就會強制執行跨源政策,且用戶端發出的任何跨網域要求都會失敗,無法與該伺服器上託管的資源互動。

一般來說,CORS 預檢要求是使用 HTTP OPTIONS 方法發出。支援 CORS 的伺服器收到 OPTIONS 要求時,會傳回一組 CORS 標頭給用戶端,指出 CORS 支援的層級。完成交握後,用戶端就會知道允許從非來源網域要求哪些內容。

如要進一步瞭解預檢,請參閱 Cross-Origin Resource Sharing W3C Recommendation。此外,還有許多關於 CORS 的網誌和文章可供參考。

Apigee 不會隨附 CORS 預檢解決方案,但您可以實作,如本節所述。目標是讓 Proxy 在條件式流程中評估 OPTIONS 要求。然後,Proxy 就能將適當的回應傳回給用戶端。

讓我們看看範例流程,然後討論處理預檢要求的相關部分:

<?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 的主要部分如下:

  • 系統會為 OPTIONS 要求建立具有條件的 NULL 目標 RouteRule。請注意,系統未指定 TargetEndpoint。如果收到 OPTIONS 要求,且 Origin 和 Access-Control-Request-Method 要求標頭不是空值,Proxy 會立即在回應中將 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 要求標頭不是空值,系統就會建立 OptionsPreFlight 流程,將含有 CORS 標頭的「新增 CORS 政策」新增至流程。
     <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>