處理錯誤

您正在查看 Apigee Edge 說明文件。
查看 Apigee X 說明文件
資訊

當 API Proxy 處理來自應用程式的要求時,可能會發生許多錯誤狀況。舉例來說,API Proxy 可能會在與後端服務進行通訊時遇到網路問題、應用程式可能會顯示過期的憑證,以及要求訊息的格式可能有誤等。

在用戶端應用程式呼叫 API Proxy 後發生錯誤,就會傳回錯誤訊息給用戶端。根據預設,用戶端通常會收到非常隱密的錯誤訊息,而且沒有詳細資料或指引。不過,如要用更實用的自訂訊息取代預設錯誤訊息,並以其他 HTTP 標頭等方式讓訊息更加豐富,您必須在 Edge 中設定自訂錯誤處理機制。

自訂錯誤處理功能也可讓您新增功能,例如每次發生錯誤時的訊息記錄。

在我們開始在您的 API Proxy 中導入自訂錯誤處理機制之前,建議您先瞭解 API Proxy 會如何發生錯誤,以及相關反應。

影片

請觀看以下影片,進一步瞭解錯誤處理。

影片 說明
錯誤處理和錯誤流程簡介 瞭解錯誤處理程序,以及 API Proxy 發生錯誤時的處理方式。
使用錯誤規則處理錯誤 瞭解如何使用錯誤規則處理錯誤。
使用 riseFault 政策提高自訂錯誤 使用 riseFault 政策在 API 執行階段引發自訂錯誤。
定義 API Proxy 和目標端點中的錯誤規則 在 API Proxy 和目標端點中定義錯誤規則,並瞭解其中差異。
瞭解錯誤規則的執行順序 瞭解 API Proxy 和目標端點中的錯誤規則執行順序。
定義預設錯誤規則 定義預設錯誤規則,以處理 API 中的一般錯誤。

錯誤發生方式

首先,我們會只說明發生錯誤的方式。瞭解錯誤發生方式後,您就可以根據您想要實作自訂錯誤處理的不同情況進行規劃。

自動錯誤

在下列情況中,API Proxy 會自動擲回錯誤:

  • 政策擲回錯誤。舉例來說,如果 API 呼叫傳送過期的金鑰,VerifyAPIKey 政策會自動擲回錯誤;或者,如果 API 呼叫數量超過特定限制,配額政策SpikeArrest 政策就會擲回錯誤。如要瞭解可擲回的錯誤類型,請參閱政策錯誤參考資料
  • API Proxy 訊息流程發生問題,例如轉送錯誤。
  • 發生後端錯誤,例如因通訊協定層級失敗、TLS/SSL 錯誤或目標服務無法使用而導致的 HTTP 錯誤。
  • 發生系統層級的故障,例如記憶體不足的例外狀況。

如要進一步瞭解這些錯誤,請參閱本主題的「錯誤分類」一節。

自訂錯誤

在沒有自動錯誤的情況下,您可能需要擲回自訂錯誤;例如,回應包含「unavailable」這個字詞,或是 HTTP 狀態碼大於 201。如要這麼做,請在 API Proxy 流程中的適當位置新增 IncreaseFault 政策

您可以將 riseFault 政策新增至 API Proxy 流程,方法與新增其他政策相同。在以下的 Proxy 設定範例中,Raise-Fault-1 政策會附加到 TargetEndpoint 回應中。如果目標服務的回應中出現「unavailable」一詞,系統會執行 IncreaseFault 政策並擲回錯誤。

<TargetEndpoint name="default">
...
  <Response>
    <Step>
      <Name>Raise-Fault-1</Name>
      <Condition>(message.content Like "*unavailable*")</Condition>
    </Step>
  </Response>

這只是要說明您可以擲回自訂錯誤。如要進一步瞭解 GrowFault 政策,請參閱「FaultRules vs. riseFault 政策」一節。

如需更多範例,請前往 Apigee 社群論壇參閱下列文章:

發生錯誤時 API Proxy 會採取什麼行動

以下是 Proxy 擲回錯誤的影響。

結束 Proxy 管道

當 API Proxy 發生錯誤時,無論原因為何,都會結束正常流程管道、進入錯誤狀態,並將錯誤訊息傳回至用戶端應用程式。API Proxy 進入錯誤狀態後,就無法將處理作業傳回至一般流程管道。

舉例來說,假設 API Proxy 在 ProxyEndpoint 要求中具有下列順序的政策:

  1. 驗證 API 金鑰
  2. 配額
  3. JSON 到 XML

如果在 API 金鑰驗證期間發生錯誤,API Proxy 會進入錯誤狀態。系統不會執行配額和 JSON 至 XML 政策、Proxy 不會導向 TargetEndpoint,並傳回錯誤訊息給用戶端應用程式。

檢查 FaultRules

如果處於錯誤狀態,API Proxy 也會依序檢查 API Proxy 設定中是否包含下列內容,然後再將預設錯誤訊息傳回用戶端應用程式:

  1. <FaultRules> 區段,其中包含的邏輯會根據您定義的特定條件觸發自訂錯誤訊息 (和其他政策)。
  2. <DefaultFaultRule> 區段,會在下列情況觸發預設錯誤訊息:
    • 未定義任何 <FaultRules>
    • 不會執行任何現有的 <FaultRules>
    • <AlwaysEnforce> 元素已設為 true。

基本上,API Proxy 可讓您傳回自訂錯誤訊息並觸發其他邏輯。如果 Proxy 沒有找到這些部分,或是這些部分皆存在,但沒有觸發自訂錯誤,Proxy 會傳送 Edge 產生的預設訊息。

簡易錯誤處理示例

我們先從簡單的範例開始,其中呼叫 API Proxy 未包含必要的 API 金鑰。根據預設,以下是傳回到用戶端應用程式的回應:

HTTP/1.1 401 Unauthorized
Date: Wed, 20 Jul 2016 19:19:32 GMT
Content-Type: application/json
Content-Length: 150
Connection: keep-alive
Server: Apigee Router

* Connection #0 to host myorg-test.apigee.net left intact
{"fault":{"faultstring":"Failed to resolve API Key variable request.queryparam.apikey","detail":{"errorcode":"steps.oauth.v2.FailedToResolveAPIKey"}}}

您的 API 使用者或許可以瞭解錯誤訊息,但可能不適用。許多預設錯誤都比較細緻,難以解密。

API 開發人員可以選擇變更這則訊息,以便滿足最終會收到錯誤訊息的使用者,無論是 iOS 應用程式開發人員,還是有本身的錯誤訊息格式規定的內部測試群組都一樣。

以下舉例說明如何建立自訂錯誤訊息來處理這項錯誤。這需要 1) 定義自訂訊息的政策,以及 2) 會在 Proxy 進入錯誤狀態時執行政策的 FaultRule。

1. 建立定義自訂訊息的政策

首先,請建立定義自訂錯誤訊息的政策。您可以使用任何類型的政策 (例如 AssignMessage 政策) 和選用的 HTTP 標頭 (例如狀態碼和原因詞組)。指派訊息有助於達成這個目標。可讓您控管訊息酬載、設定不同的 HTTP 狀態碼、設定不同的 HTTP 原因詞組,以及新增 HTTP 標頭。

請勿將這項政策附加至 API Proxy 中的任何流程。只需包含在 Proxy 組合中即可。如要在管理 UI Proxy 編輯器中執行這項操作,請前往「開發」分頁,然後在「導覽」窗格中按一下「政策」列上的「+」圖示。

這樣做可讓您建立政策,而不必將其附加至 API Proxy 中的資料流。凡是未附加至任何流程的政策,都會在政策清單中以「卸離」圖示標記,如上圖所示的 API 金鑰訊息政策旁。

以下是 AssignMessage 政策的範例:

  • 傳回 JSON 訊息。
  • 設定 HTTP 狀態碼 (911,這是一個明顯不存在的狀態碼,僅用於說明您具備的彈性)。狀態碼會顯示在 HTTP 標頭中。
  • 設定 HTTP 原因詞組 (取代此缺少 API 金鑰錯誤的預設「未授權」原因詞組)。原因詞組會顯示在 HTTP 標頭中的狀態碼旁邊。
  • 建立並填入名為 invalidKey 的新 HTTP 標頭。
<AssignMessage async="false" continueOnError="false" enabled="true" name="invalid-key-message">
    <DisplayName>Invalid key message</DisplayName>
    <Set>
        <Payload contentType="application/json">{"Citizen":"Where's your API key? I don't see it as a query parameter"}</Payload>
        <StatusCode>911</StatusCode>
        <ReasonPhrase>Rejected by API Key Emergency Services</ReasonPhrase>
    </Set>
    <Add>
        <Headers>
            <Header name="invalidKey">Invalid API key! Call the cops!</Header>
        </Headers>
    </Add>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

執行這項政策時,對用戶端應用程式的回應如下所示。 然後與先前顯示的預設回應進行比較。

HTTP/1.1 911 Rejected by API Key Emergency Services
Date: Wed, 20 Jul 2016 18:42:36 GMT
Content-Type: application/json
Content-Length: 35
Connection: keep-alive
invalidKey: Invalid API key! Call the cops!
Server: Apigee Router

* Connection #0 to host myorg-test.apigee.net left intact
{"Citizen":"Where's your API key? I don't see it as a query parameter."}

沒錯,這有點傻,但其實是你還有可能的。現在,開發人員在收到訊息時,就知道他們忘了加入 API 金鑰做為查詢參數。

不過,Google 如何執行這項政策?下一個部分會顯示。

2. 建立會觸發政策的 <FaultRule>

在 Proxy 設定的 <ProxyEndpoint><TargetEndpoint> 區段中,您將新增包含一或多個個別 <FaultRule> 區段的 <FaultRules> XML 區塊。每個 FaultRule 都代表您想處理的不同錯誤。在這個範例中,我們只會使用一個 FaultRule 來顯示組成內容。

如未執行任何 FaultRules,您也應新增 <DefaultFaultRule>,以提供自訂的一般錯誤訊息。

範例

<ProxyEndpoint name="default">
...
    <FaultRules>
       <FaultRule name="invalid_key_rule">
            <Step>
                <Name>invalid-key-message</Name>
            </Step>
            <Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
        </FaultRule>
    </FaultRules>
    <DefaultFaultRule name="default-fault">
        <Step>
            <Name>Default-message</Name>
        </Step>
    </DefaultFaultRule>

重點:

  • FaultRules 於 ProxyEndpoint 中定義。這很重要,進一步瞭解如何將 FaultRules 新增至 ProxyEndpoint 和 TargetEndpoint。
  • <Name>:要執行的政策名稱。這個名稱取自父項元素的政策 name 屬性,如前文政策範例所示。
  • <Condition> - Edge 會評估條件,並只在條件為 true 時執行政策。如果有多個 FaultRules 評估結果為 true,Edge 會執行第一個為 true 的 FaultRules。(重要事項:FultRules 的評估順序,由上到下,由下到上) 在 TargetEndpoint 和 ProxyEndpoint 之間有不同的評估順序,詳情請參閱多個 FaultRules 和執行邏輯一節。)如果您沒有加入條件,FultRule 會自動為 True。但這不是最佳做法。每個 FaultRule 都應有各自的條件。

  • <DefaultFaultRule> - 如未執行任何自訂 FaultRule,系統就會執行 <DefaultFaultRule>,並傳送較一般的自訂訊息,而非隱密的預設 Edge 產生的訊息。<DefaultFaultRule> 也可以包含 <Condition>,但是在大多數情況下,您不會加入一個,因為您只有在萬不得已時,都需要執行這個函式。

    DefaultFaultRule 通常用於針對任何非預期錯誤傳回一般錯誤訊息。例如,訊息中包含技術支援的聯絡資訊。這個預設回應有兩個目的,就是為了提供適合開發人員的資訊,同時也需要模糊處理後端網址或其他可能會用於入侵系統的資訊。

多個 FaultRules 和執行邏輯

在「簡易錯誤處理範例」一節中,我們使用單一 FaultRule 和限制條件的簡單範例。在實際的 API 專案中,且可能發生所有可能的錯誤,您的 <ProxyEndpoint><TargetEndpoint> 可能都包含多個 FaultRules 和 DefaultFaultRule。但最終,當 API Proxy 進入錯誤狀態時,系統只會執行一個 FaultRule。

本節說明 Edge 在處理 FaultRules 時使用的邏輯,包括如何抵達單一 FaultRule 以及「內部」步驟條件在觸發 FaultRule 時的處理方式。本節也會說明在 <ProxyEndpoint><TargetEndpoint> 中定義 FaultRules 的時機,並說明 FaultRules 和 IncreaseFault 政策之間的關係。

FaultRules 執行作業

簡單來說,以下是 API Proxy 進入錯誤狀態時使用的邏輯 Edge。請注意,ProxyEndpoint 與 TargetEndpoint 的 FaultRules 評估有些微差異。

  1. 邊緣會根據錯誤發生的位置,評估 ProxyEndpoint 或 TargetEndpoint 中的 FaultRules:
    • ProxyEndpoint - Edge 在設定 XML 中的「底部」<FaultRule> 開始,然後開始評估每個 <FaultRule><Condition> (「外部」條件,而不是「內部」<Step> 條件)。
    • TargetEndpoint - 邊緣從設定 XML 中的頂端 <FaultRule> 開始,然後向下開始評估每個 <FaultRule><Condition> (「外部」條件,而不是「內部」<Step> 條件)。
  2. 執行條件為 true 的第一個 FaultRule。如果 FaultRule 沒有條件,則預設為 true。
    • 執行 FaultRule 時,系統會依序評估 FaultRule 中的所有步驟,也就是 XML 設定中由上到下的。系統會自動執行沒有條件的步驟 (執行政策),以及 <Condition> 評估為「true」的步驟 (系統不會執行評估結果為「false」的條件)。
    • 如果已執行 FaultRule,但沒有執行 FaultRule 中的步驟 (因為其條件評估結果為「false」),則 Edge 產生的預設錯誤訊息會傳回給用戶端應用程式。而「不會」執行 <DefaultFaultRule>,因為 Edge 已經執行其一項 FaultRule。

  3. 如未執行 FaultRule,Edge 會執行 <DefaultFaultRule> (如果有的話)。

以下是包含內嵌註解的範例。

ProxyEndpoint 執行作業

ProxyEndpoint FaultRules 的評估由下至上,因此請開始閱讀以下範例中的最後一個 FaultRule,並逐步思考。請查看最後的 DefaultFaultRule。

<ProxyEndpoint name="default">
...
    <FaultRules>
<!-- 3. This FaultRule is automatically TRUE, because there's no "outer" 
     condition. But because the FaultRule just below this got
     executed (bottom-to-top evaluation in a ProxyEndpoint), Edge
     doesn't even evaluate this FaultRule.
     Note that it's not a best practice to have a FaultRule without 
     an outer condition, which automatically makes the FaultRule true. -->
        <FaultRule name="random-error-message">
            <Step>
                <Name>Random-fault</Name>
            </Step>
        </FaultRule>
<!-- 2. Let's say this fault is TRUE. The Quota policy threw a QuotaViolation
     error. This is the first FaultRule to be TRUE, so it's executed. 
     Now the Steps are evaluated, and for the ones whose conditions
     evaluate to TRUE, their policies are executed. Steps without
     conditions are automatically true. -->
<FaultRule name="over_quota">
            <Step>
                <Name>developer-over-quota-fault</Name>
                <Condition>(ratelimit.developer-quota-policy.exceed.count GreaterThan "0")</Condition>
            </Step>
            <Step>
                <Name>global-over-quota-fault</Name>
                <Condition>(ratelimit.global-quota-policy.exceed.count GreaterThan "0")</Condition>
            </Step>
            <Step>
                <Name>log-error-message</Name>
            </Step>
            <Condition>(fault.name = "QuotaViolation")</Condition>
        </FaultRule>
<!-- 1. Because this is the ProxyEndpoint, Edge looks at this FaultRule
     first. But let's say this FaultRule is FALSE. A policy did not 
     throw a FailedToResolveAPIKey error. Edge moves UP to check
     the next FaultRule. -->
        <FaultRule name="invalid_key_rule">
            <Step>
                <Name>invalid-key-message</Name>
            </Step>
            <Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
        </FaultRule>
    </FaultRules>

<!-- If no <FaultRule> is executed, the <DefaultFaultRule> is executed. 
     If a FaultRule is executed, but none of its Steps are executed,
     The DefaultFaultRule is not executed (because Edge has already
     executed its one FaultRule). -->
    <DefaultFaultRule name="default-fault">
        <Step>
            <Name>Default-message</Name>
        </Step>
    </DefaultFaultRule>

目標端點執行作業

系統會從上到下評估 TargetEndpoint FaultRules,因此建議您從下列範例中的第一項 FaultRule 開始閱讀,然後逐步完成。請查看最後的 DefaultFaultRule。

<TargetEndpoint name="default">
...
    <FaultRules>
<!-- 1. Because this is the TargetEndpoint, Edge looks at this FaultRule
     first. Let's say this FaultRule is FALSE. 
     A policy did not throw a FailedToResolveAPIKey error. 
     Edge moves down to the next FaultRule. -->
        <FaultRule name="invalid_key_rule">
            <Step>
                <Name>invalid-key-message</Name>
            </Step>
            <Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
        </FaultRule>
<!-- 2. Let's say this fault is TRUE. The Quota policy threw a QuotaViolation
     error. This is the first FaultRule to be TRUE, so it's executed. 
     Now the Steps are evaluated, and for the ones whose conditions
     evaluate to TRUE, their policies are executed. Steps without
     conditions are automatically true. -->
        <FaultRule name="over_quota">
            <Step>
                <Name>developer-over-quota-fault</Name>
                <Condition>(ratelimit.developer-quota-policy.exceed.count GreaterThan "0")</Condition>
            </Step>
            <Step>
                <Name>global-over-quota-fault</Name>
                <Condition>(ratelimit.global-quota-policy.exceed.count GreaterThan "0")</Condition>
            </Step>
            <Step>
                <Name>log-error-message</Name>
            </Step>
            <Condition>(fault.name = "QuotaViolation")</Condition>
        </FaultRule>
<!-- 3. This FaultRule is automatically TRUE, because there's no "outer" 
     condition. But because the FaultRule just above this got
     executed (top-to-bottom evaluation in a TargetEndpoint), Edge
     doesn't even evaluate this FaultRule.
     Note that it's not a best practice to have a FaultRule without 
     an outer condition, which automatically makes the FaultRule true. -->
        <FaultRule name="random-error-message">
            <Step>
                <Name>Random-fault</Name>
            </Step>
        </FaultRule>
    </FaultRules>

<!-- If no <FaultRule> is executed, the <DefaultFaultRule> is executed. 
     If a FaultRule is executed, but none of its Steps are executed,
     The DefaultFaultRule is not executed (because Edge has already
     executed its one FaultRule). -->
    <DefaultFaultRule name="default-fault">
        <Step>
            <Name>Default-message</Name>
        </Step>
    </DefaultFaultRule>

錯誤規則順序

如上一個範例所示,FultRules 的放置順序非常重要,取決於該錯誤是在 ProxyEndpoint 還是 TargetEndpoint 中發生。

例如:

ProxyEndpoint 順序 TargetEndpoint 順序

在以下範例中,由於評估結果由下至上,因此系統會執行 FaultRule 3,這表示系統不會評估 FaultRules 2 和 1。

5. FaultRule 1:FALSE

4. FaultRule 2:TRUE

3. FaultRule 3:TRUE

2. FaultRule 4:FALSE

1. FaultRule:5 FALSE

在以下範例中,由於評估由上至下,因此系統會執行 FaultRule 2,這表示不會評估 FaultRules 3、4、5。

1. FaultRule 1:FALSE

2. FaultRule 2:TRUE

3. FaultRule 3:TRUE

4. FaultRule 4:FALSE

5. FaultRule:5 FALSE

要納入的政策

您可以在「步驟」中加入 FaultRule 中的任何政策。舉例來說,您可以執行 AssignMessage 政策來設定用戶端應用程式的回應格式,然後使用 MessageLogging 政策記錄訊息。系統會依照您放置政策的順序執行 (在 XML 中由上到下)。

「只會」處於錯誤狀態而觸發錯誤規則 (aboutContinueOnError)

這個標頭看似我們會重複出現,但其中仍有一項特殊的細微差異,在於導致 API Proxy 進入錯誤狀態的 Proxy 錯誤,或是「不是」輸入錯誤狀態:政策中的 continueOnError 屬性。

重點回顧:「只有」在 Proxy 進入錯誤狀態時,API Proxy 才會評估 <FaultRules><DefaultFaultRule>。這表示即使 FaultRule 條件評估為 true,在 Proxy 未處於錯誤狀態時,也不會觸發該條件。

不過,以下是發生錯誤,以及 Proxy 未輸入錯誤狀態的示例。在任何政策中,您都可以在名為 continueOnError 的父項元素上設定屬性。 該屬性對錯誤處理來說非常重要,因為它會判斷 Proxy 是否在政策失敗時進入錯誤狀態。在大多數情況下,您可以保留預設的 continueOnError="false",當政策失敗時,Proxy 就會處於錯誤狀態,並觸發自訂錯誤處理程序。不過,如果 continueOnError="true" (例如,您不希望服務呼叫失敗以停止 Proxy 執行),當這項政策失敗時,Proxy 不會進入錯誤狀態,且 Proxy 也不會查看 FaultRules。

如要瞭解如何在 continueOnError="true" 時記錄錯誤,請參閱「在目前流程中處理政策錯誤」。

定義 FaultRules 的位置:ProxyEndpoint 或 TargetEndpoint

API Proxy 發生錯誤時,<ProxyEndpoint> (來自用戶端應用程式的要求或回應) 或 <TargetEndpoint> (目標服務的要求或回應) 中都會發生錯誤。無論發生這種錯誤,Edge 都會尋找 FaultRules。

舉例來說,如果目標伺服器無法使用 (HTTP 狀態碼 503),API Proxy 會在 <TargetEndpoint> 回應中進入錯誤狀態,而一般 API Proxy 流程不會繼續進入 <ProxyEndpoint>。如果您只在 <ProxyEndpoint> 中定義 FaultRules,這些規則就不會處理該項錯誤。

我們再看另一個例子如果 <ProxyEndpoint> 回應中的 IncreaseFault 政策觸發錯誤,系統就不會執行 <TargetEndpoint> 中的 FaultRule。

FaultRules 與 GrowFault 政策的比較

錯誤規則和 riseFault 政策可能會以另一種方式處理錯誤,例如完成錯誤處理的替代方式;而這可能會在某些方面派上用場。但這兩者也可搭配運作,本節將說明這兩者之間的關係。瞭解這種關係應有助於設計錯誤處理程序,特別是當您想同時使用兩者時。

簡單來說:

  • 當 API Proxy 進入錯誤狀態時,系統一律會評估不良規則
  • RaiseFault 政策可讓您在錯誤未發生的情況下,將 API Proxy 設為錯誤狀態。

    舉例來說,如果您希望在目標服務的回應中,傳回 HTTP 狀態碼大於 200 時擲回錯誤,請在回應流程中新增 IncreaseFault 政策。網址看起來會像這樣:

    <TargetEndpoint name="default">
        <PreFlow name="PreFlow">
    ...
            <Response>
                <Step>
                    <Name>Raise-Fault-1</Name>
    <!-- If the condition is true, the Raise-Fault-1 policy gets executed -->
                    <Condition>(response.status.code GreaterThan "200")</Condition>
                </Step>
            </Response> 
    

    GrowFault 政策也會將錯誤訊息傳送至用戶端應用程式。

如果 PromoteFault 政策觸發了錯誤,導致 Proxy 處於錯誤狀態,則可能會執行 FaultRule,會發生什麼事?以下說明在操作上更得心應手的地方。如果 riseFault 政策傳回錯誤訊息,並且觸發 FaultRule 並傳回錯誤訊息,什麼內容會傳回到用戶端應用程式?

  • 由於 FaultRule 或 DefaultFaultRule 是在 riseFault 政策之後執行,因此 FaultRule 回應資料會勝出。
  • 如果 FaultRule 或 DefaultFaultRule 未設定資料,就會使用 riseFault 政策回應資料 (狀態碼、原因詞組或訊息酬載)。
  • 如果 PromoteFault 政策和 FaultRule 都新增了自訂 HTTP 標頭,則兩者都會包含在回應中。重複的標頭名稱會建立含有多個值的標頭。

以下範例說明 自 李 Fault 政策和 FaultRule 的設定,以及傳回到用戶端應用程式的內容。範例旨在保持精簡,而非採用最佳做法。

用戶端應用程式接收

Status Code: 468
Reason Phrase: Something happened
Payload: {"Whoa":"Sorry."}
Header: 
  errorNote: woops,gremlins

<- 未通過規則政策設定

Status Code: [none] 
Reason Phrase: Something happened
Payload: {"Whoa":"Sorry."}
Header: 
  errorNote: gremlins

<- riseFault 政策設定此項

Status Code: 468
Reason Phrase: Can't do that
Payload: {"DOH!":"Try again."}
Header: 
  errorNote: woops

建築物條件

條件是 FaultRule 執行作業的關鍵。建立 FaultRule 條件的方式與 Edge 中的其他條件相同,例如針對條件式流程或 riseFault 條件。

為了讓本節的其餘部分更完整,以下提供含有 outer FaultRule 條件和內部步驟條件的錯誤規則範例。

<FaultRule name="invalid_key_rule">
    <Step>
        <Name>invalid-key-message</Name>
        <Condition>(oauthV2.Verify-API-Key-1.failed = true)</Condition>
    </Step>
    <Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
</FaultRule>

政策錯誤特有的變數

當政策擲回錯誤時,可用 fault.name{policy_namespace}.{policy_name}.failed 變數。

fault.name

當政策失敗時,請使用 fault.name 變數擷取條件中的錯誤。例如:

<Condition>(fault.name = "policy_error_name")</Condition>

錯誤名稱會顯示在預設錯誤訊息中。例如,以下範例中的錯誤名稱為 FailedToResolveAPIKey。在此情況下,名為 fault.name 的資料流變數會設為 FailedToResolveAPIKey 值。

{"fault":{"faultstring":"Failed to resolve API Key variable request.queryparam.apikey","detail":{"errorcode":"steps.oauth.v2.FailedToResolveAPIKey"}}}

因此條件看起來會像這樣:

<Condition>(fault.name = "FailedToResolveAPIKey")</Condition>

如需政策錯誤清單,請參閱政策錯誤參考資料

「{policy_namespace}.{policy_name}」失敗

當政策失敗時,可以使用 *.failed 變數。以下是不同政策的 *.failed 變數範例。如需政策命名空間,請參閱每個政策參考資料主題中的流程變數。

其他可用變數

當 API Proxy 進入錯誤狀態時,唯一可在條件中使用的變數如下:

  • 失敗的政策變數。
  • 失敗時出現的 HTTP 訊息變數。舉例來說,如果回應擲回錯誤,<TargetEndpoint> 中的 FaultRule 就能使用 HTTP 資料 response.status.codemessage.contenterror.content 等。或者,如果配額政策失敗,您也可以使用 ratelimit.{quota_policy_name}.exceed.count 變數。使用追蹤工具政策參考主題,協助您找出可用的變數和 HTTP 資料。

更多資訊

錯誤處理的最佳做法

錯誤處理是 API Proxy 開發的主要架構設計工作。請務必花時間瞭解處理錯誤的方式和時間、決定訊息內容,以及設計錯誤訊息格式。釐清以上事項後,請利用這些最佳做法來協助您執行錯誤處理作業。

以下是設計及建構錯誤處理的一些最佳做法:

  • 針對每個 FaultRule,提供「外部」<Condition> (屬於 <Step> 元素)。沒有外部條件的失敗規則會自動評估為 true。「內部」步驟條件不會用於判斷 FaultRule 為 True 或 False。只有在 Edge 執行包含這些步驟的 FaultRule 後,才會評估步驟條件。在 FaultRule 中,往往有多個步驟具有「指派訊息」(或其他) 政策,而且每個步驟都有「Step」條件。
  • 如要處理同一類型的多項政策 (例如多個配額政策) 中的錯誤,請為您可能會收到的每個政策錯誤建立一項 FaultRule。舉例來說,您可以針對配額政策中可能出現的每個錯誤 (例如 QuotaViolationInvalidMessageWeightStartTimeNotSupported) 建立 FaultRule。(請參閱「政策錯誤參考資料」瞭解政策錯誤;發現其他需要處理的錯誤時,可以稍後再返回將錯誤新增至 FaultRules。可以疊代,但需要重新部署 Proxy。)如此一來,無論擲回哪個政策,這個方法都能擷取同類型的錯誤,進而提高 FaultRules XML 的效率。

    如果您需要更精細的錯誤控制項,請使用內部步驟條件。舉例來說,假設您在要求流程中同時強制執行個人開發人員配額和全域配額,且其中包含兩項政策,請設定「outer」FultRule 條件,以便在 QuotaViolation 錯誤發生時觸發 (這類錯誤會在配額耗盡時擲回)。接著設定步驟條件,評估兩項配額政策中的 exceed.count 變數。只有相關錯誤才會傳送至用戶端 (開發人員配額超額或全域配額超額)。設定範例如下:

    <FaultRule name="over_quota">
    <!-- This condition catches a QuotaViolation in *any* Quota policy -->
      <Condition>(fault.name = "QuotaViolation")</Condition>
      <Step>
        <Name>developer-over-quota-fault</Name>
        <Condition>(ratelimit.developer-quota-policy.exceed.count GreaterThan "0")</Condition>
      </Step>
      <Step>
        <Name>global-over-quota-fault</Name>
        <Condition>(ratelimit.global-quota-policy.exceed.count GreaterThan "0")</Condition>
      </Step>
    </FaultRule>
    

    如需其他範例,請參閱這個 Apigee 社群討論串

  • 如要在使用單一類型的政策時處理錯誤,請考慮在一項政策失敗時執行的單一錯誤規則,以及包含對應至各個可能錯誤的多個步驟。這樣可以讓 XML 有效率,使用單一 FaultRule 而非多個 FaultRules (每種錯誤類型各一個)。例如:

    <FaultRule name="raise-fault-3">
    <!-- This condition catches *any* error in the Verify-API-Key-1 policy. -->
      <Condition>(oauthV2.Verify-API-Key-1.failed = "true")</Condition>
      <!-- This first step always executes, which handles errors you haven't mapped with inner conditions. -->
      <Step>
        <Name>Generic-Key-Fault</Name>
      </Step>
      <Step>
        <Name>Assign-Message-Raise-Fault-1</Name>
        <Condition>(fault.name = "FailedToResolveAPIKey")</Condition>
      </Step>
      <Step>
        <Name>Assign-Message-Raise-Fault-2</Name>
        <Condition>(fault.name = "InvalidApiKey")</Condition>
      </Step>
    </FaultRule>
    
  • 新增發生錯誤的 FaultRules (用戶端 <ProxyEndpoint> 或目標端 <TargetEndpoint>),並針對每個位置顯示的各項政策加入 FaultRules。
  • 在 FaultRules 中,您可以執行任何類型的政策,以將訊息傳回用戶端應用程式。AssignMessage 政策最為實用。如果您想追蹤錯誤,也請考慮使用 MessageLogging 政策記錄訊息。
  • 將 riseFault 政策與 FaultRules 搭配使用時,請協調在 riseFault 政策和 FaultRule 傳回資料時,所傳送的回應資料。舉例來說,如果您的 IncreaseFault 政策重設 HTTP 狀態碼,請不要使用 FaultRule 重設狀態碼。最糟的情況是,預設狀態碼會傳回給用戶端應用程式。
  • <DefaultFaultRule> 執行作業:
    • 如果希望在沒有其他 FaultRule 的情況下一律執行 <DefaultFaultRule>,則請勿在其中加入 <Condition>
    • 如果希望在執行其他 FaultRule 時一律執行 <DefaultFaultRule>,請新增 <AlwaysEnforce>true</AlwaysEnforce> 子元素。

集中式、可重複使用的錯誤處理模式

以下 Apigee 社群貼文描述了在不複製程式碼的情況下,集中式錯誤處理的模式:

https://community.apigee.com/articles/23724/an-error-handling-pattern-for-apigee-proxies.html

建立 FaultRules

如要新增 FaultRule,您必須編輯 ProxyEndpoint 或 TargetEndpoint 的 XML 設定。您可以使用 Edge UI 在 API Proxy 的「Develop」(開發) 檢視畫面的「Code」窗格中編輯,或是編輯定義 ProxyEndpoint 或 TargetEndpoint 的 XML 檔案。

如果您是在管理 UI 中建立 FaultRules,請先建立您要執行的政策,然後將其新增至 FaultRule 設定。(如果您嘗試儲存的 FaultRule 參照尚未建立的政策,使用者介面就會顯示錯誤)。

將政策新增至 FaultRule

雖然您可以在 FaultRule 中加入任何政策,但通常會使用 AssignMessage 政策產生錯誤條件的自訂回應訊息。AssignMessage 可讓您設定內含酬載、HTTP 狀態碼、標頭和原因詞組元素的 HTTP 回應。

以下為一般的 AssignMessage 政策設定範例:

<AssignMessage name="fault_invalidkey">
  <Set>
      <Payload contentType="text/plain">Contact support at support@mycompany.com.</Payload>
      <StatusCode>401</StatusCode>
      <ReasonPhrase>Unauthorized</ReasonPhrase>
  </Set>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</AssignMessage>

您現在可以在 FaultRule 中使用這項政策。請注意如何在 FaultRule 中依名稱參照 AssignMessage 政策:

<ProxyEndpoint name="default">
  ...
  <FaultRules>
    <FaultRule name="invalid_key_rule">
      <Step>
        <Name>fault_invalidkey</Name>
      </Step>
      <Condition>(fault.name = "InvalidApiKey")</Condition>
    </FaultRule>
  </FaultRules>
</ProxyEndpoint>

部署上述設定時,每當應用程式顯示無效的 API 金鑰時,API Proxy 就會執行名為 fault_invalidkey 的 AssignMessage 政策。

您可以在 FaultRule 中執行多項政策,如以下範例所示:

<ProxyEndpoint name="default">
  ...
  <FaultRules>
    <FaultRule name="invalid_key_rule">
      <Step>
        <Name>policy1</Name>
      </Step>
      <Step>
        <Name>policy2</Name>
      </Step>
      <Step>
        <Name>policy3</Name>
      </Step>
      <Condition>(fault.name = "InvalidApiKey")</Condition>
    </FaultRule>
  </FaultRules>
</ProxyEndpoint>

政策會依照定義的順序執行。例如,您可以使用 MessageLogging 政策擷取變數政策AssignMessage 政策或任何其他 FaultRule 中的其他政策。請注意,如果發生下列任一情況,系統就會立即停止處理 FaultRule:

  • FaultRule 中的任何政策都會導致錯誤
  • FaultRule 中的任何政策都屬於 riseFault 類型

定義 FaultRule 傳回的自訂錯誤訊息

最佳做法是,從 API 定義明確的錯誤回應。這樣才能向客戶提供一致且實用的資訊。

下列 AssignMessage 政策範例使用 <Payload><StatusCode><ReasonPhase> 標記來定義發生 InvalidApiKey 錯誤時傳回至用戶端的自訂錯誤回應 (請參閱先前的 FaultRules 範例)。

<AssignMessage name="fault_invalidkey">
  <Set>
    <Payload contentType="text/plain">You have attempted to access a resource without the correct authorization. 
       Contact support at support@mycompany.com.</Payload>
    <StatusCode>401</StatusCode>
    <ReasonPhrase>Unauthorized</ReasonPhrase>
  </Set>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</AssignMessage>

這則回應包括:

  • 酬載包含錯誤訊息,以及用來聯絡支援團隊的電子郵件地址。
  • 回應中傳回的 HTTP 狀態碼。
  • 原因詞組,為錯誤的簡短說明。

建立 DefaultFaultRule

發生任何未明確由其他 FaultRule 處理的錯誤時,DefaultFaultRule 就會是例外狀況處理常式。如果所有 FaultRules 的條件與錯誤不符,DefaultFaultRule 就會處理錯誤。將 <DefaultFaultRule> 標記新增為 ProxyEndpoint 或 TargetEndpoint 的子項元素,即可啟用預設的錯誤處理功能。

舉例來說,以下的 TargetEndpoint 設定定義了可叫用名為 ReturnGenericError 的政策的 DefaultFaultRule:

<TargetEndpoint name="default">
  ...
  <FaultRules>
    ...
  </FaultRules>

  <DefaultFaultRule name="fault-rule">
    <Step>
      <Name>ReturnGenericError</Name>
    </Step>
  </DefaultFaultRule>

  <HTTPTargetConnection>
    <URL>http://mocktarget.apigee.net</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

DefaultFaultRule 通常用於在發生任何非預期的錯誤時傳回一般錯誤訊息,例如訊息中包含技術支援的聯絡資訊。這個預設回應有兩個目的,就是為了提供適合開發人員的資訊,同時也需要模糊處理後端網址或其他可能會用於入侵系統的資訊。

舉例來說,您可以定義下列 AssignMessage 政策來傳回一般錯誤:

<AssignMessage name="ReturnGenericError">
  <Set>
    <Payload type="text/plain">SERVICE UNAVAILABLE. PLEASE CONTACT SUPPORT: support@company.com.</Payload>
  </Set>
</AssignMessage>

<DefaultFaultRule> 標記中加入 <AlwaysEnforce> 元素,即可對各項錯誤執行 DefaultFaultRule,即使已執行其他 FaultRule 也一樣。DefaultFaultRule 一律是最後一個執行的 FaultRule:

  <DefaultFaultRule name="fault-rule">
    <Step>
      <Name>ReturnGenericError</Name>
    </Step>
    <AlwaysEnforce>true</AlwaysEnforce>
  </DefaultFaultRule>

DefaultFaultRule 的一種用途,是判斷在他人無法判斷時發生的錯誤類型。例如,因無法判斷錯誤,導致 API Proxy 失敗。使用 DefaultFaultRule 叫用以下 AssignMessage 政策。這項政策會將 fault.name 值寫入回應中名為 DefaultFaultHeader 的標頭:

<AssignMessage async="false" continueOnError="false" enabled="true" name="DefaultFaultRule">
  <DisplayName>DefaultFaultRule</DisplayName>
  <Set>
    <Headers>
      <Header name="DefaultFaultHeader">{fault.name}</Header>
    </Headers>
  </Set>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

然後,您就可以在 Edge 追蹤工具或回應中查看標頭,瞭解導致錯誤的原因。

在 PostClientFlow 中新增訊息記錄

PostClientFlow 是在 Proxy 進入錯誤狀態後執行的唯一流程。只有 MessageLogging 政策可以附加至這個流程,這個流程會在回應傳回用戶端後執行。雖然將 MessageLogging 政策附加至這個流程並不會處理錯誤,但您可以將其用來記錄錯誤事件中的資訊。無論 Proxy 是成功或失敗,系統都會執行此作業,因此您可以將訊息記錄政策放入 PostClientFlow 中,並確保其一律會執行。

在目前的流程中處理政策錯誤

目前為止顯示的範例均使用 ProxyEndpoint 或 TargetEndpoint 的 FaultRule,以便處理因錯誤狀態而發生的任何政策錯誤。這是因為政策中 continueOnError 元素的預設值是 false。也就是說,當政策發生錯誤時,控制項會導向錯誤狀態。進入錯誤狀態後,您就無法將控制權交還回一般管道,而且通常會將某種形式的錯誤訊息傳回呼叫應用程式。

但是,如果您將政策的 continueOnError 元素設為 true,控制項會留在目前的流程中,而在導致錯誤的政策後,管道中的下一項政策會繼續執行。在目前流程中處理錯誤的優勢,在於您可以復原錯誤來完成要求處理作業。

下圖顯示名為 verify-api-keyVerifyAPIKey 政策,且 continueOnError 元素已設為 true:

<VerifyAPIKey async="false" continueOnError="true" enabled="true" name="verify-api-key">
  <DisplayName>Verify API Key</DisplayName>
  <APIKey ref="request.queryparam.apikey"/>
</VerifyAPIKey>

如果 API 金鑰遺失或無效,VerifyAPIKey 政策會將 oauthV2.verify-api-key.failed 變數設為 true,但會在目前的流程中繼續進行處理作業。

接著,您就能在 ProxyEndpoint 的 PreFlow 中,以步驟新增 VerifyAPIKey 政策:

<ProxyEndpoint name="default">
  ...
  <PreFlow name="PreFlow">
    <Request>
      <Step>
        <Name>verify-api-key</Name>
      </Step>
      <Step>
        <Name>FaultInFlow</Name>
        <Condition>(oauthV2.verify-api-key.failed = "true")</Condition>
      </Step>
    </Request>
    <Response/>
  </PreFlow>      
</ProxyEndpoint>  

請注意,PreFlow 的下一個步驟如何使用條件來測試錯誤是否存在。如果 VerifAPIKey 政策發生錯誤,系統會執行名為 FaultInFlow 政策的政策。否則,系統會略過 FaultInFlow 政策。FaultInFlow 政策可以執行多項操作,例如記錄錯誤、嘗試修正錯誤或執行其他動作。

使用 riseFault 政策觸發錯誤

您隨時可以在流程中使用 IncreaseFault 政策來觸發錯誤。執行 upsFault 政策時,會終止目前的資料流,並將控制項轉移至錯誤狀態。

UpFault 政策的其中一種用途是測試其他政策可能無法偵測到的特定條件。在上述範例中,您已在 PreFlow <Step> 標記中加入 <Condition> 標記,並在符合條件時執行政策 FaultInFlow。如果 FaultInFlow 是 upsFault 政策,則請控制轉移至錯誤狀態的移轉作業。或者,您可以在流程中插入 riseFault 政策,以便偵錯及測試 FaultRules。

當 GrowFault 政策觸發錯誤時,您可以使用下列 FaultRule 和條件來處理問題:

<FaultRule name="raisefault_rule">
  <Step>
    <Name>{policy_name}</Name>
  </Step>
  <Condition>(fault.name = "RaiseFault")</Condition>
</FaultRule>

請注意,條件測試是針對名為 RaiseFault 的錯誤。ObservFault 政策一律會將 fault.name 的值設為 RaiseFault

目標伺服器提供的 HTTP 錯誤代碼自訂處理方式

上節中的示例適用於政策建立的錯誤。不過,您也可以針對傳輸層級錯誤建立自訂回應,也就是目標伺服器傳回的 HTTP 錯誤。如要控制 HTTP 錯誤的回應,請設定 TargetEndpoint,以便處理 HTTP 回應代碼。

根據預設,Edge 會將 1xx-3xx 範圍內的 HTTP 回應代碼視為「成功」,並將 4xx-5xx 範圍內的 HTTP 回應代碼視為「failure」。也就是說,從後端服務傳送任何 HTTP 回應代碼 4xx-5xx 的回應,會自動叫用錯誤狀態,進而將錯誤訊息直接傳回要求用戶端。

您可以為任何 HTTP 回應代碼建立自訂處理常式。舉例來說,您可能不想將 4xx-5xx 範圍中的所有 HTTP 回應代碼都視為「失敗」,但只處理 5xx,或者想要針對 HTTP 回應代碼 400 和 500 傳回自訂錯誤訊息。

在下一個範例中,您使用了 success.codes 屬性來設定 TargetEndpoint,以及預設的 HTTP 代碼,將 HTTP 回應代碼 400 和 500 視為成功。將這些代碼視為成功後,TargetEndpoint 接手處理回應訊息,而非叫用錯誤狀態:

<TargetEndpoint name="default">
  ...
  <HTTPTargetConnection>
    <Properties>
          <Property name="success.codes">1xx,2xx,3xx,400,500</Property>
    </Properties>
    <URL>http://weather.yahooapis.com</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

如本範例所示,您可以使用萬用字元,將 success.codes 屬性設為某個值範圍。

設定 success.codes 屬性會覆寫預設值。因此,如果您想將 HTTP 代碼 400 加入預設成功代碼清單中,請將這個屬性設為:

<Property name="success.codes">1xx,2xx,3xx,400</Property>

不過,如果只想將 HTTP 代碼 400 視為成功代碼,請將屬性設為:

<Property name="success.codes">400</Property>

您現在可以為 HTTP 回應代碼 400 和 500 定義自訂處理常式,將自訂回應訊息傳回給提出要求的應用程式。以下 TargetEndpoint 使用名為 ReturnError 的政策來處理 HTTP 400 和 500 回應代碼:

<TargetEndpoint name="default">
  <PreFlow name="PreFlow">
    <Request/>
    <Response>
      <Step>
        <Name>ReturnError</Name>
        <Condition>(response.status.code = 400) or (response.status.code = 500)</Condition>
      </Step>
    </Response>
  </PreFlow>

  <HTTPTargetConnection>
    <Properties>
      <Property name="success.codes">1xx,2xx,3xx,400,500</Property>
    </Properties>
    <URL>http://weather.yahooapis.com</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

這個 TargetEndpoint 設定會讓名為 ReturnError 的政策在 TargetEndpoint 出現 HTTP 回應代碼 400 或 500 時處理回應。

錯誤分類

API 服務會將錯誤分為下列類別和子類別。

類別 子類別 錯誤名稱 說明
訊息 訊息流程期間發生的錯誤 (不含政策失敗記錄)
自訂錯誤 {fault_name} 由 API Proxy 使用 riseFault 政策明確處理的任何錯誤
回應碼 InternalServerError、NotFound HTTP 錯誤代碼 5xx、4xx
轉送失敗 NoRoutesMatched 對要求選取已命名的 TargetEndpoint 失敗
分類失敗 NotFound 因要求 URI 與任何 ProxyEndpoint 設定的任何 BasePath 都不相符而造成的錯誤 (也就是說,沒有任何 API Proxy 與用戶端應用程式要求中的網址相符)
交通 HTTP 傳輸層級錯誤
連線能力 ConnectionRefused、ConnectionReset、ConnectionTimeout 建立網路或傳輸層級連線時發生失敗
要求驗證 ContentLengthMissing、HostHeaderMissing 對每項要求的語意檢查期間發生錯誤
回應驗證 對每個回應進行語意檢查時出現錯誤
I/O 錯誤 SSLHandshakeError、ReadTimeout、ReadError、WriteTimeout、WriteError、ChunkError 用戶端或目標端點的讀取/寫入錯誤、逾時、TLS/SSL 錯誤,以及區塊錯誤
系統 未定義的執行階段錯誤
記憶體容量 OutOfMemory、GCOverLimit 記憶體相關故障
討論串 RogueTaskTerminated 失敗,例如終止執行工作
政策 如需各種政策類型的錯誤定義,請參閱政策參考資料

錯誤一律會附上說明失敗原因的文字說明。系統引發錯誤時,系統會填入一組屬性,協助排解問題。錯誤包含以下資訊:

  • 原因
  • 使用者定義的自訂屬性