500 內部伺服器錯誤 - BadFormData

您目前查看的是 Apigee Edge 說明文件。
前往 Apigee X 說明文件。
info

問題

用戶端應用程式會收到 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
    • 如果表單資料量不大,系統會以鍵/值組合的形式傳送資料,並使用:
      • 兩個金鑰中的字元都必須按照 表單 - 第 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 公有和私有雲使用者

常見的診斷步驟

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

API Monitoring

如要使用 API 監控功能診斷錯誤,請按照下列步驟操作:

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

  3. 依序前往「Analyze」>「API Monitoring」>「Investigate」頁面。
  4. 選取您觀察到錯誤的特定時間範圍。
  5. 繪製「錯誤代碼」與「時間」的關係圖。

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

    (查看較大圖片)

  7. 故障代碼 protocol.http.BadFormData 的相關資訊會顯示如下:

    (查看較大圖片)

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

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

追蹤工具

如要使用「追蹤」工具診斷錯誤,請按照下列步驟操作:

  1. 啟用追蹤工作階段 和下列任一項目:
    • 等待發生 500 Internal Server Error 錯誤,或
    • 如果可以重現問題,請發出 API 呼叫來重現問題 500 Internal Server Error
  2. 確認已啟用「顯示所有流程資訊」:

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

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

  6. 前往特定政策失敗後的「Error」流程:

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

    錯誤:Bad Form Data

    state: PROXY_REQ_FLOW

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

    • 錯誤 Bad Form Data 的值表示表單參數含有不允許使用的字元。
    • 狀態 PROXY_REQ_FLOW, 的值表示 API Proxy 的要求流程發生錯誤。
  8. 在追蹤記錄中前往「AX」(記錄的 Analytics 資料)AX 階段,然後按一下該階段。
  9. 向下捲動至「Phase Details - Error Headers」部分,並判斷 X-Apigee-fault-code、X-Apigee-fault-source 和 X-Apigee-fault-policy 的值,如下所示:

  10. 請注意,X-Apigee-fault-code 和 X-Apigee-fault-source 的值分別為 protocol.http.BadFormData 和 policy,且 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-policy 為 extractvariables/EV- ExtractFormParams, ,表示名為「ExtractVariables」的政策在讀取或擷取表單參數時失敗。EV-ExtractFormParams

NGINX

如要使用 NGINX 存取記錄診斷錯誤,請按照下列步驟操作:

  1. 如果您是私有雲使用者,可以透過 NGINX 存取記錄判斷 HTTP 500 Internal Server Error 的金鑰資訊。
  2. 檢查 NGINX 存取記錄:

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

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

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

    上述 NGINX 存取記錄檔的範例項目具有下列 X-Apigee-fault-code 和 X-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-code 和 X-Apigee-fault-source 的值分別為 protocol.http.BadFormData 和 policy ,且 X-Apigee-fault-policy 不為空白。這表示 X-Apigee-fault-policy 中指定的特定政策在讀取或擷取表單資料 (表單參數) 時發生錯誤,因為表單資料含有不允許使用的字元。
  6. 在本例中,X-Apigee-fault-policy 為 extractvariables/EV- ExtractFormParams, ,表示名為 EV-ExtractFormParams 的 ExtractVariables 政策在讀取表單參數時失敗。

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

診斷

  1. 如常見診斷步驟所述,使用 API Monitoring、Trace 工具或 NGINX 存取記錄,判斷 500 Internal Server Error 的錯誤代碼、錯誤來源和錯誤政策。
  2. 如果「錯誤代碼」為 protocol.http.BadFormData,「錯誤來源」的值為 proxy 或 policy,且「錯誤政策」不為空白,則表示系統在讀取或擷取表單資料 (表單參數) 時,「錯誤政策」中指定的政策失敗。
  3. 檢查「Fault Policy」(錯誤政策) 中指出的政策,並判斷下列資訊:
    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> 元素表示

      • 表單參數: username 和 password

        <FormParam> 元素中的 <Pattern> 元素會指出這點

      這表示用戶端透過 HTTP 要求傳送至 Apigee Edge 的表單參數 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 屬性會指出這點

      • 表單參數: username 和 password

        <FormParam> 元素中的 name 屬性會指出這點

      這表示用戶端傳送至 Apigee Edge 的 HTTP 要求中,包含usernamepassword不允許使用的字元。

  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. 如果無法存取向目標伺服器提出的實際要求,請前往「解決方法」。
    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 名稱
  • 用於重現 500 Internal Server Error 的完整 curl 指令,以及錯誤代碼 protocol.http.BadFormData
  • API 要求的追蹤記錄檔

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

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

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

    說明: ORG、ENV 和 PORT# 會替換為實際值。

  • 訊息處理器系統記錄

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

參考資料