500 內部伺服器錯誤 - BadFormData

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

問題

用戶端應用程式會取得 500 Internal Server Error 的 HTTP 狀態碼,以及錯誤代碼 protocol.http.BadFormData 做為 API 呼叫的回應。

錯誤訊息

用戶端應用程式會取得以下回應代碼:

HTTP/1.1 500 Internal Server Error

此外,您可能會遇到以下錯誤訊息:

{
   "fault":{
      "faultstring":"Bad Form Data",
      "detail":{
         "errorcode":"protocol.http.BadFormData"
      }
   }
}

表單資料

在深入說明如何解決這個問題前,請先瞭解什麼是表單資料。

表單資料是使用者通常透過 HTML 表單提供的資訊,其中包含文字輸入方塊、按鈕或核取方塊等元素。表單資料通常會以一系列鍵/值組合的形式傳送,做為 HTTP 要求或回應的一部分。

表單資料傳輸

  1. Content-Type: application/x-www-form-urlEncoding
    • 如果表單資料的大小很小,資料會以鍵/值組合的形式傳送,其中包含:
      • 兩個索引鍵中編碼的字元,如 表單 - 第 17.13.4.1 節所述規則
      • 標題 Content-Type: application/x-www-form-urlencoded

      包含表單資料的要求示例:

      curl https://HOSTALIAS/somepath -H "Content-Type: application/x-www-form-urlencoded" -d "username=abc@google.com&pasword=secret123"
      
    • 鍵和值中的任何非英數字元都會 編碼百分比,也就是以字元三元組 %HH 表示,包含百分比符號後接兩個十六進位數字,代表特定字元的 ASCII 代碼。
    • 因此,即使表單資料可以使用百分比符號 (%),仍會被解讀為特殊逸出序列的起始。因此,如果表單資料需要在鍵或值中包含百分比符號 (%),則應以 %25, 代表百分比符號 (%) 字元的 ASCII 編碼。
  2. Content-Type:Multipart/form-data

    如要傳輸大量的二進位資料或包含非 ASCII 字元的文字,您可以按照 表單 - 第 17.13.4.2 節的說明,透過 Content-Type: multipart/form-data 傳送資料。

可能原因

只有在符合下列所有條件時,才會發生這個錯誤:

  1. 用戶端傳送至 Apigee Edge 的 HTTP 要求包含下列內容:
    1. Content-Type: application/x-www-form-urlencoded
    2. 含有百分比符號 (%) 或百分比符號 (%) 的表單資料,後面接著禁止使用的十六進位字元,如 表單 - 第 17.13.4.1 節所述。
  2. Apigee Edge 中的 API Proxy 會透過「ExtractVariables」或 AssignMessage 政策,讀取特定表單參數,其中包含不允許在要求流程中使用的字元。

    舉例來說,如果表單資料包含原狀 (%) 原樣 (不含編碼) 或百分比符號 (%),後接鍵和/或值中的任何無效的十六進位字元,就會發生這個錯誤。

    這項錯誤的可能原因如下:

    原因 說明 適用的疑難排解指示
    要求中的表單參數含有不允許的字元 用戶端在 HTTP 要求中傳遞的表單參數包含任何不允許使用的字元。 Edge Public and Private Cloud 使用者

常見診斷步驟

請使用下列其中一種工具/技巧診斷這項錯誤:

API Monitoring

如何使用 API Monitoring 診斷錯誤:

  1. 適當角色的身分 登入 Apigee Edge UI
  2. 切換至您想要調查問題的機構。

  3. 前往「分析」>「API 監控」>「調查」頁面。
  4. 請選取你發現錯誤的特定時間範圍。
  5. 將「Fault Code」與「Time」進行比較。

  6. 選取含有錯誤代碼 protocol.http.BadFormData 的儲存格,如下所示:

    (查看較大的圖片)。

  7. 錯誤代碼 protocol.http.BadFormData 的相關資訊如下所示:

    (查看較大的圖片)。

  8. 按一下「查看記錄」,然後展開失敗要求的資料列。

  9. 在「記錄檔」視窗中記下下列詳細資料:
    • 狀態碼: 500
    • Fault 資料來源: proxy
    • 錯誤代碼: protocol.http.BadFormData
    • 違規政策: extractvariables/EV-ExtractFormParams
  10. 如果「Fault Source」proxy、「Fault Code」protocol.http.BadFormData 且「Fault Policy」 非空白,表示發生錯誤時,「Fault Policy」中指定政策讀取或擷取的表單資料 (表單參數) 含有任何不允許使用的字元。
  11. 在這個範例中,X-Apigee-fault-policyextractvariables/EV- ExtractFormParams, ,這表示讀取或擷取表單參數時,名為 EV-ExtractFormParams 的 ExtractVariables 政策失敗。

追蹤工具

如何使用追蹤工具診斷錯誤:

  1. 啟用追蹤工作階段,然後採取下列其中一種做法:
    • 等待發生 500 Internal Server Error 錯誤,或
    • 如果可以重現問題,請透過 API 呼叫來重現問題 500 Internal Server Error
  2. 確保已啟用「Show all FlowInfos」

  3. 請選取其中一個失敗的要求,然後檢查追蹤記錄。
  4. 瀏覽追蹤記錄的不同階段,找出發生錯誤的位置。
  5. 一般來說,您會在其中一項政策中找到該錯誤,如下所示:

    請注意,在上述範例追蹤記錄中,名為 EV-ExtractFormParams 的「ExtractVariables」政策中發生錯誤。

  6. 在特定政策失敗後,前往名為 Error 的流程:

  7. 記下追蹤記錄中的下列值:

    錯誤:Bad Form Data

    州:PROXY_REQ_FLOW

    error.class: com.apigee.rest.framework.BadRequestException

    • 錯誤 Bad Form Data 值表示表單參數中含有「不允許」使用的字元。
    • 狀態 PROXY_REQ_FLOW, 表示 API Proxy 要求流程中發生錯誤。
  8. 前往追蹤記錄中的「AX」(Analytics (分析) 已記錄) 階段,然後按一下該階段。
  9. 向下捲動至「階段詳細資料」-「錯誤標頭」區段,確定 X-Apigee-fault-codeX-Apigee-fault-sourceX-Apigee-fault-policy 的值,如下所示:

  10. 請注意,X-Apigee-fault-codeX-Apigee-fault-source 的值分別為 protocol.http.BadFormDatapolicy,且 X-Apigee-fault-policy 非空白。這表示在 X-Apigee-fault-policy 中指出的特定政策是讀取或擷取表單資料 (表單參數),其中包含任何不允許使用的字元。

    回應標頭
    X-Apigee-fault-code protocol.http.BadFormData
    X-Apigee-fault-source policy
    X-Apigee-fault-policy extractvariables/EV-ExtractFormParams
  11. 在這個示例中,X-Apigee-fault-policyextractvariables/EV- ExtractFormParams, ,代表在讀取或擷取表單參數時,名為 EV-ExtractFormParams 的 ExtractVariables 政策失敗。

NGINX

如何使用 NGINX 存取記錄檔診斷錯誤:

  1. 如果您是 Private Cloud 使用者,即可使用 NGINX 存取記錄檔來判斷 HTTP 500 Internal Server Error 的重要資訊。
  2. 查看 NGINX 存取記錄檔:

    /opt/apigee/var/log/edge-router/nginx/ORG~ENV.PORT#_access_log

  3. 搜尋特定期間內 (問題過去是否發生),或是否有任何要求仍為 500 失敗,且錯誤代碼為 protocol.http.BadFormData500
  4. 如果發現 X-Apigee-fault-codeprotocol.http.BadFormData 值相符的任何 500 錯誤,請判斷 X-Apigee-fault-sourceX-Apigee-fault-policy 的值。

    NGINX 存取記錄中的 500 錯誤範例:

    以上 NGINX 存取記錄中的範例項目,有下列「X-Apigee-fault-code」X-Apigee-fault-code和「X-Apigee-fault-source」X-Apigee-fault-code的值:

    標頭
    X-Apigee-fault-code protocol.http.BadFormData
    X-Apigee-fault-source policy
    X-Apigee-fault-policy extractvariables/EV-ExtractFormParams
  5. 請注意,X-Apigee-fault-codeX-Apigee-fault-source 的值為 protocol.http.BadFormDatapolicy 各自為 protocol.http.BadFormDataX-Apigee-fault-policy 非空白。這表示在 X-Apigee-fault-policy, 中指出的特定政策期間,當錯誤發生時,會讀取或擷取表單資料 (表單參數),其中包含任何X-Apigee-fault-policy,使用的字元。
  6. 在這個示例中,X-Apigee-fault-policyextractvariables/EV- ExtractFormParams, ,代表在讀取表單參數時,名為 EV-ExtractFormParams 的 ExtractVariables 政策失敗。

原因:要求中的表單參數含有不允許使用的字元

診斷

  1. 使用 API 監控、追蹤工具或 NGINX 存取記錄檔,按照常見診斷步驟的說明,判斷 500 Internal Server Error不良程式碼錯誤來源不良政策
  2. 如果「Fault Code」protocol.http.BadFormData,「Fault Source」的值為 proxypolicy,而「Fault Policy」不為空白,則表示在讀取或擷取表單資料 (表單參數) 時,Fault Policy 中指定的政策失敗。
  3. 請詳閱「Fault 政策」中列出的政策,並判斷下列資訊:
    1. 來源:判斷政策是否正在讀取或擷取要求或回應中的資料。
    2. 表單參數:判斷在政策中讀取的特定表單參數。

      範例 #1

      範例 #1:擷取變數政策擷取表單參數:

            <ExtractVariables name="EV-ExtractFormParms">
               <DisplayName>EV-ExtractFormParams</DisplayName>
               <Source>request</Source>
               <FormParam name="username">
                  <Pattern ignoreCase="false">{username}</Pattern>
               </FormParam>
               <FormParam name="password">
                 <Pattern ignoreCase="false">{password}</Pattern>
               </FormParam>
               <VariablePrefix>forminfo</VariablePrefix>
             <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
            </ExtractVariables>
            

      在上述「ExtractVariables」政策中:

      • 資料來源:request

        <Source> 元素所示

      • 表單參數: usernamepassword

        <FormParam> 元素中的 <Pattern> 元素,就表示

      這表示用戶端向 Apigee Edge 在 HTTP 要求中傳遞的表單參數 username 和/或 password 包含不允許使用的字元。

      範例 #2

      範例 #2:AssignMessage 政策複製表單參數:

            <AssignMessage continueOnError="false" enabled="true" name="AM-CopyFormParams">
              <Copy source="request">
                <FormParams>
                  <FormParam name="username"/>
                  <FormParam name="password"/>
                </FormParams>
              </Copy>
              <AssignTo createNew="true" transport="http" type="request"/>
            </AssignMessage>
            

      在上述「ExtractVariables」政策中:

      • 來源:request

        <Copy> 元素中的 source 屬性來表示

      • 表單參數: usernamepassword

        <FormParam> 元素中的 name 屬性來表示

      這表示 usernamepassword 表單參數 usernamepassword 格式在用戶端向 Apigee Edge 的 HTTP 要求中傳遞,包含任何「不允許」使用的字元。

  4. 透過下列其中一種方法,查看步驟 3 中是否有任何字元「不允許」使用字元:

    追蹤工具

    如何使用追蹤工具進行驗證:

    1. 如果您已擷取失敗要求的追蹤記錄 (如常見診斷步驟中所述),請選取其中一個失敗的要求。
    2. 如果您確定表單參數包含「不允許」使用的任何字元,請參閱上述步驟 3 中的 HTTP 要求,然後:
      1. 前往「Request Received from Client」階段。
      2. 向下捲動至「階段詳細資料」部分並查看「要求內容」

        ( 查看較大圖片)。

      3. 在上述範例中,請注意,表單參數 password 包含百分比符號 (%)。
      4. 由於百分比符號 (%) 也會用於特殊字元的 百分比編碼,因此無法原封不動在表單資料中使用。
      5. 因此,Apigee Edge 會以 500 Internal Server Error 傳回錯誤代碼 protocol.http.BadFormData

    實際要求

    如何使用實際要求進行驗證:

    1. 如果您無法存取對目標伺服器實際發出的要求,請前往「Resolution」
    2. 如果您可以存取對 Apigee Edge 傳送的實際要求,請執行下列步驟:
      1. 檢查表單資料內容,看看其中是否含有任何不允許使用的字元,例如百分比符號 (%) 或百分比符號 (%) 後面接著無效的十六進位字元。

        範例 #1

        要求範例 #1:要求中的表單資料

        curl -X GET "https://HOSTALIAS/myproxy -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=123456abc123&client_secret=c23578%ZY"
        

        在此範例中,請注意,元素 client_secret 包含百分比符號 (%),後面接著無效的十六進位字元 ZY

        範例 #2

        要求範例 #2:透過檔案傳送的表單資料:

        curl -X GET "https://HOSTALIAS/myproxy -H "Content-Type: application/x-www-form-urlencoded" -d @form_data.xml
        

        form_data.xml 的內容:

        xml=<user><username>abc1234@google.com</username><password>qwerty12345!@#$%</password></user>
        

        在此範例中,請注意,元素 password 包含百分比符號 (%),不應在表單資料中原封不動地傳遞。

    3. 在上述兩個範例中,做為 Apigee Edge 以 HTTP 要求形式傳送的表單資料,含有不允許使用的字元。
    4. 因此,Apigee Edge 會以 500 Internal Server Error 傳回錯誤代碼 protocol.http.BadFormData

解析度

  1. 確保在用戶端透過 HTTP 要求傳送的表單資料或參數值中,兩者的特殊字元,一律會採用 表單資料 - application/x-www-form-urlcoded 所述編碼。
  2. 針對上述的例子,您可以修正下列問題:

    範例 #1

    範例 1:在要求中傳送的表單資料:

    請使用符合 ASCII 代碼的特定字元 十六進位字元。舉例來說,如要傳送錢幣符號 ($),請使用 %24,如下所示:

    curl -X GET "https://HOSTALIAS/myproxy -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=123456abc123&client_secret=c23578%24"
    

    範例 #2

    要求範例 #2:透過檔案傳送的表單資料:

    curl -X GET "https://HOSTALIAS/myproxy -H "Content-Type: application/x-www-form-urlencoded" -d @form_data.xml
    

    form_data.xml 的內容:

    請使用百分比 (%) 符號的 百分比編碼來修改檔案,使其包含 %25 ,如下所示:

    xml=<user><username>abc1234@google.com</username><password>qwerty12345!!@#$%25</password></user>
    

規格

Apigee Edge 預期會以下列規格傳送表單資料

規格
表單資料 - application/x-www-form-urlcoded

如果您仍需取得 Apigee 支援團隊的協助,請參閱「必須收集診斷資訊」一文。

必須收集診斷資訊

如果按照上述指示操作後仍無法解決問題,請收集下列診斷資訊,然後與 Apigee Edge 支援團隊聯絡:

如果您是公開雲端使用者,請提供下列資訊:

  • 機構組織名稱
  • 環境名稱
  • API Proxy 名稱
  • 完成 curl 指令,用來重現 500 Internal Server Error 錯誤代碼 protocol.http.BadFormData
  • API 要求的追蹤檔

如果您是 Private Cloud 使用者,請提供下列資訊:

  • 觀察失敗要求的完整錯誤訊息
  • 環境名稱
  • API Proxy 套裝組合
  • API 要求的追蹤檔
  • NGINX 存取記錄檔

    /opt/apigee/var/log/edge-router/nginx/ORG~ENV.PORT#_access_log

    其中:ORGENVPORT# 替換為實際值。

  • 訊息處理器系統記錄

    /opt/apigee/var/log/edge-message-processor/logs/system.log

參考資料