500 內部伺服器錯誤 - BadFormData

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

問題

用戶端應用程式收到 HTTP 狀態碼 500 Internal Server Error, 錯誤代碼 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-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 文字的文字 字元,那麼您可以使用 Content-Type: multipart/form-data,詳情請參閱 Google 表單 - 第 17.13.4.2 節

可能原因

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

  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 要求中傳遞的表單參數包含任何 不允許使用的字元。 邊緣公有雲和私有雲使用者

常見的診斷步驟

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

API Monitoring

如何使用 API Monitoring 診斷錯誤:

  1. 以使用者身分登入 Apigee Edge UI 適當角色
  2. 切換到您要調查問題的機構。

  3. 前往「Analyze」(分析) >「API 監控 >調查頁面。
  4. 請選取您發現錯誤的確切時間範圍。
  5. 根據「時間」繪製「Fault Code」指標。

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

    (查看較大的圖片)。

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

    (查看較大的圖片)。

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

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

追蹤工具

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

  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」AX(已記錄 Analytics 資料) 階段,然後按一下 基礎架構
  9. 向下捲動至「Phase Details」-「Error Headers」部分 確定 X-Apigee-fault-codeX-Apigee-fault-source 的值。 和 X-Apigee-fault-policy,如下所示:

  10. 請注意,X-Apigee-fault-codeX-Apigee-fault-source 的值為 分別為 protocol.http.BadFormDatapolicyX-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 無法讀取或擷取表單 參數。

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.BadFormData (如果發生問題的話) ) 或是發生任何請求失敗 500
  4. 如果發現任何含有 X-Apigee-fault-code500 錯誤 與 protocol.http.BadFormData 的值相符,然後 確定 X-Apigee-fault-source 的價值 X-Apigee-fault-policy.

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

    上述 NGINX 存取記錄的範例項目如下 X-Apigee-fault-codeX-Apigee-fault-source:

    標頭
    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 X-Apigee-fault-policy 並未空白。這表示 出現於 X-Apigee-fault-policy, 中特定政策時, 讀取或擷取表單資料 (表單參數),其中包含任何 禁止使用
  6. 在這個範例中,X-Apigee-fault-policyextractvariables/EV- ExtractFormParams, ,代表名稱為 EV-ExtractFormParams無法讀取表單 參數。

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

診斷

  1. 使用 API 監控、追蹤工具或 NGINX 存取記錄,判斷 500 Internal Server Error 的「錯誤程式碼」、「錯誤來源」和「錯誤政策」。 「常見診斷步驟」一節。
  2. 如果「Fault Code」protocol.http.BadFormData,則「Fault Source」為 值 proxypolicy,以及 Fault Policy 為非 ,空白,則代表「錯誤政策」,中指定的政策無法在 讀取或擷取表單資料 (表單參數)。
  3. 詳閱「錯誤政策」一節中所述的政策,並確認下列事項: 每個 ACL 都由一或多個項目組成 而這些項目包含兩項資訊
    1. 來源:判斷政策正在讀取還是擷取資料 要求或回應
    2. 表單參數:決定要在 政策。

      範例 #1

      示例 1:擷取表單參數的 ExtractVariables 政策:

            <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

        這項機制是由 <Pattern> 元素中的 <FormParam> 個元素

      這表示表單參數 username 和/或 password 做為 HTTP 要求的一部分,由用戶端傳遞至 Apigee Edge 含有禁止使用的字元。

      範例 #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

        這項指令會由 source 屬性中的 <Copy> 個元素

      • 表單參數: usernamepassword

        這項指令會由 name 屬性中的 <FormParam> 個元素

      這表示表單參數為 usernamepassword 或 並透過用戶端傳送至 Apigee Edge 的 HTTP 要求,其中包含 所不允許使用的字元。

  4. 檢查是否有「不允許」的字元 步驟 3 中找到的表單參數中使用的字元 類型:

    追蹤工具

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

    1. 如果您已擷取失敗要求的追蹤記錄, 常見診斷步驟,然後選取其中一個 傳回的結果
    2. 如果您確定表單參數包含任何字元 「禁止」用於 HTTP 要求 上方的步驟 3,然後
      1. 前往「Request Received from Client」階段。
      2. 向下捲動至「Phase Details」部分,並查看 請求內容

        ( 查看較大的圖片)

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

    實際要求

    如要使用實際要求進行驗證,請按照下列步驟操作:

    1. 如果您無法存取對目標伺服器發出的實際要求, 前往「解析度」
    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. 在以上兩個範例中,表單資料是透過 HTTP 要求的一部分傳送至 Apigee Edge 含有禁止使用的字元。
    4. 因此,Apigee Edge 會以 500 Internal Server Error 回應 並傳回錯誤代碼 protocol.http.BadFormData

解析度

  1. 確認表單資料或參數形式的鍵和值中的所有特殊字元 做為 HTTP 要求的一部分,則一律會予以編碼,如 表單資料 - application/x-www-form-urlencoded
  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-urlencoded

如果您仍需 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

參考資料