為 API Proxy 新增 CORS 支援

查看 Apigee Edge 說明文件。
前往 Apigee X說明文件
資訊

CORS (跨源資源共享) 是允許 JavaScript 的標準機制 在網頁中執行 XMLHttpRequest (XHR) 呼叫,以便與非來源的資源互動 網域。CORS 是針對「同源政策」的常見解決方案執行 。舉例來說,如果您透過 JavaScript 程式碼向 Twitter API 發出 XHR 呼叫 就會失敗。這是因為 您的瀏覽器與提供 Twitter API 的網域不同。CORS 會提供解決方案 請先允許伺服器「選擇採用」如果客戶想提供跨來源資源 分享。

影片:觀看這部短片,瞭解如何在 API Proxy 上啟用 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,並在 Proxy 上呼叫 Service API 後端。請記住,Edge 位於用戶端 (在此案例中為瀏覽器) 和後端之間 API (服務)。由於 API Proxy 是在伺服器上執行,而非在瀏覽器中執行, 可以成功呼叫服務。接著,您只需要 將 CORS 標頭附加至 TargetEndpoint 回應。只要瀏覽器支援 CORS 這些標頭告訴瀏覽器可以「放鬆」同源政策 才能成功傳送

建立支援 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 政策附加至新的 API Proxy

您可以在 API Proxy 中新增 CORS 支援,方法是附加「新增 CORS」政策套用至 API Proxy 建立容器若要新增這項政策,請勾選 [新增 CORS 標頭] 核取方塊 「Build a Proxy」精靈的「Security」(安全性) 頁面

勾選這個核取方塊後,系統就會自動將名為「新增 CORS」的政策加入系統中 並附加至目標端點回應預流,如下圖所示:

在政策下方將 CORS 政策新增至導覽器,並附加至目標端點回應預先流程中

新增 CORS 政策做為 AssignMessage 政策進行實作, 會在回應中加入適當的標頭 基本上,標頭可讓瀏覽器知道要與哪個來源共用資源。 接受的方法等等如要進一步瞭解這些 CORS 標頭,請參閱 跨來源資源分享 W3C 建議

請按照下列步驟修改政策:

  • Access-Control-Allow-Headers 標頭中加入 content-typeauthorization 標頭 (支援基本驗證或 OAuth2,如下方程式碼片段所示)。
  • 如要使用 OAuth2 驗證,您可能需要採取相關措施來修正不符合 RFC 規定的行為
  • 建議您使用 <Set> 設定 CORS 標頭,而不是 <Add>,如下方節錄內容所示。 使用 <Add> 時,如果 Access-Control-Allow-Origin 標頭已存在,您會收到下列錯誤訊息:

    The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

    如需詳細資訊,請參閱 CORS 錯誤:標頭包含多個值「*, *」,但只允許一個值。

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

將 CORS 標頭新增至現有的 Proxy

您需要手動建立新的「指派訊息」政策,並複製新增 CORS 的程式碼 提及政策。然後將政策附加至 API Proxy 的目標端點您可以視需要修改標頭值。如要 如要進一步瞭解如何建立並附加政策,請參閱「什麼是政策?」一文。

處理 CORS 預檢要求

CORS 預檢是指傳送要求至伺服器來驗證 支援 CORS一般預檢回應包含伺服器接受 CORS 的來源 要求,亦即 CORS 要求支援的 HTTP 方法清單, 做為資源要求的一部分,可以快取預檢回應時間上限;以及 和其他。如果服務未表示支援 CORS,或不想接受跨源 用戶端來源的要求時,系統將強制執行瀏覽器的跨來源政策,並 用戶端提出的任何跨網域要求,可與代管伺服器上的資源互動 失敗。

CORS 預檢要求通常會使用 HTTP OPTIONS 方法提出。如果伺服器 支援 CORS 會收到 OPTIONS 要求, 則會傳回一組 CORS 標頭給用戶端 指出其 CORS 支援層級。憑藉這次握手的結果,用戶端瞭解 允許從非來源網域提出要求。

如要進一步瞭解預檢,請參閱跨來源資源分享 W3C 建議。有 CORS 相關網誌和文章可供您參考。

Apigee 未提供立即可用的 CORS 預檢解決方案,但您可以在 按照本節所述的方式實作目的是讓 Proxy 評估選項 要求存取權接著 Proxy 就能將適當的回應傳回 用戶端。

我們來看看範例流程,然後討論處理預檢要求的各個部分:

<?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.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
   </RouteRule>
   <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
</ProxyEndpoint>

這個 ProxyEndpoint 的重要部分如下:

  • 系統會建立 RouteRule 至 NULL 目標,其中包含 OPTIONS 要求的條件。請注意, 尚未指定目標端點。如果收到 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>
    
  • 建立 OptionsPreFlight 流程,新增包含 CORS 的 CORS 政策 標頭,如果接收到 OPTIONS 要求,且 Origin 與 Access-Control-Request-Method 要求標頭並非空值。

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

使用範例 CORS 解決方案

您可以在 GitHub 取得以共用流程實作的範例 CORS 解決方案。 將共用流程套件匯入環境,並使用流程掛鉤,或直接附加至 API Proxy 流程。詳情請參閱 隨附範例的 CORS-Shared-FLow README 檔案。