您正在查看 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,以便在後端呼叫服務 API。請記住,Edge 位於用戶端 (在此例中為瀏覽器) 和後端 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 政策附加至新的 API Proxy
如要為 API Proxy 新增 CORS 支援,您可以在建立 API Proxy 時將「新增 CORS」政策附加至 API Proxy。如要新增這項政策,請在「建構 Proxy」精靈的「安全性」頁面中,勾選「新增 CORS 標頭」核取方塊。
當您勾選這個核取方塊時,系統會自動將名為「Add CORS」的政策新增至系統,並附加至目標端點回應預先流程,如下圖所示:
新增 CORS 政策是以 AssignMessage 政策的形式實作,這項政策會在回應中新增適當的標頭。 基本上,標頭會告知瀏覽器要將資源與哪些來源共用,以及接受哪些方法等。如要進一步瞭解這些 CORS 標頭,請參閱跨源資源共享 W3C 建議。
您必須修改政策,如下所示:
- 在
Access-Control-Allow-Headers
標頭中加入content-type
和authorization
標頭 (支援基本驗證或 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 評估條件流程中的 OPTIONS 要求。接著,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 的重要部分如下:
- 系統會為設有 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>
- 系統會建立 OptionsPreFlight 流程,以便在接收到 OPTIONS 要求,且 Origin 和 Access-Control-Request-Method 要求標頭並非空值時,將新增 CORS 政策 (包含 CORS 標頭) 新增至流程中。
<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-F 低 README 檔案。