500 内部服务器错误 - BadFormData

<ph type="x-smartling-placeholder"></ph> 您正在查看 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 <ph type="x-smartling-placeholder">
      </ph>
    • 如果表单数据较小,则数据以键值对的形式发送,其中包含: <ph type="x-smartling-placeholder">
        </ph>
      • 两个键中的字符已根据 <ph type="x-smartling-placeholder"></ph> 表单 - 第 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"
      
    • 键和值中的任何非字母数字字符均 <ph type="x-smartling-placeholder"></ph> 使用百分比编码,即以三字符组的形式表示这些字符, %HH,由一个百分号后跟两位十六进制数字组成 代表特定字符的 ASCII 代码。
    • 因此,即使表单数据中允许使用百分号 (%), 作为特殊转义序列的开头。因此,如果表单数据需要 键或值中包含百分号 (%),则应将其传输 为 %25, ,它表示百分号的 ASCII 码 (%) 个字符。
  2. Content-Type: multipart/form-data

    如果您要传输大量二进制数据或包含非 ASCII 的文本 那么您可以使用 Content-Type: multipart/form-data,如 表单 - 第 17.13.4.2 节

可能的原因

当且仅当满足以下所有条件时,才会发生此错误:

  1. 客户端向 Apigee Edge 发送的 HTTP 请求包含: <ph type="x-smartling-placeholder">
      </ph>
    1. Content-Type: application/x-www-form-urlencoded
    2. 带有百分号 (%) 或百分号的表单数据 (%) 后跟以下不允许使用的无效十六进制字符: <ph type="x-smartling-placeholder"></ph> 表单 - 第 17.13.4.1 节
  2. Apigee Edge 中的 API 代理可读取包含任何字符的特定形式参数 不允许通过 ExtractVariables 或 AssignMessage 政策。

    例如,如果表单数据原样包含百分号 (%)(没有 编码)或百分号 (%),后跟任何无效的十六进制 键和/或值的字符,就会收到此错误。

    以下是导致此错误的可能原因:

    原因 说明 适用的问题排查说明
    请求中的表单参数包含禁用字符 客户端作为 HTTP 请求的一部分传递的表单参数包含 禁止使用的字符。 Edge 公有云和私有云用户

常见诊断步骤

使用以下工具/技术之一来诊断此错误:

API 监控

<ph type="x-smartling-placeholder">

如需使用 API Monitoring 诊断错误,请执行以下操作:

  1. <ph type="x-smartling-placeholder"></ph> 以拥有 相应角色
  2. 切换到您要在其中调查问题的单位。

  3. 导航至分析 >API 监控 >调查页面。
  4. 选择您观察到错误的具体时间范围。
  5. 根据时间绘制错误代码

    <ph type="x-smartling-placeholder">
  6. 选择错误代码为protocol.http.BadFormData的单元格 如下所示:

    查看放大图片

  7. 有关错误代码 protocol.http.BadFormData 的信息是 如下所示:

    查看放大图片

  8. 点击查看日志,然后展开失败请求对应的行。

  9. 日志窗口中,请注意以下详细信息: <ph type="x-smartling-placeholder">
      </ph>
    • 状态代码500
    • 故障来源proxy
    • 错误代码protocol.http.BadFormData
    • 故障政策extractvariables/EV-ExtractFormParams
  10. 如果故障来源proxy,则故障代码protocol.http.BadFormDataFault Policy 为非空,则它 表示错误发生时,错误 Policy 读取或提取表单数据(表单参数)时, 禁止使用的字符。
  11. 在此示例中,X-Apigee-fault-policyextractvariables/EV- ExtractFormParams, ,这意味着名为 EV-ExtractFormParams 在读取或提取表单时失败 参数。

跟踪工具

<ph type="x-smartling-placeholder">

如需使用跟踪工具诊断错误,请执行以下操作:

  1. 启用跟踪会话 以及: <ph type="x-smartling-placeholder">
      </ph>
    • 等待发生 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 代理的请求流程中。
  8. 进入跟踪记录中的 AX(记录的 Google Analytics 数据)阶段,然后点击 。
  9. 向下滚动到 Stage Details - Error Headers 部分,然后 确定 X-Apigee-fault-codeX-Apigee-fault-source 的值, 和 X-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未能读取或提取表单 参数。

NGINX

<ph type="x-smartling-placeholder">

如需使用 NGINX 访问日志诊断错误,请执行以下操作:

  1. 如果您是私有云用户,则可以使用 NGINX 访问日志 确定有关 HTTP 500 Internal Server Error 的关键信息。
  2. 查看 NGINX 访问日志:

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

    <ph type="x-smartling-placeholder">
  3. 搜索是否存在任何带有错误代码的 500 错误 protocol.http.BadFormData(如果问题 或者是否还有任何请求仍失败, 500
  4. 如果您确实在 X-Apigee-fault-code 中找到了任何 500 错误 与 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. 如果故障代码protocol.http.BadFormData,则故障来源proxypolicy故障政策为非 空白,则表示,中指定的政策 读取或提取表单数据(表单参数)。
  3. 检查故障政策中指明的政策并确定以下内容 信息: <ph type="x-smartling-placeholder">
      </ph>
    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 或 两者均作为 HTTP 请求的一部分由客户端传递给 Apigee Edge,其中包含任何 不允许使用的字符。

  4. 检查是否存在不允许的任何字符 第 3 步中确定的表单参数中使用的字符 使用以下任一方法:

    跟踪工具

    如需使用跟踪工具进行验证,请执行以下操作:

    1. 如果您已经捕获失败请求的跟踪记录,如 常见的诊断步骤,然后选择 失败的请求。
    2. 如果您已确定表单参数中包含 不允许使用 第 3 步,则 <ph type="x-smartling-placeholder">
        </ph>
      1. 进入从客户端收到的请求阶段。
      2. 向下滚动到阶段详情部分,并查看 请求内容

        ( 查看大图

      3. 请注意,在上面的示例中,表单形参 password 包含百分号 (%)。
      4. 由于百分号 (%) 也用于 <ph type="x-smartling-placeholder"></ph> 百分号编码特殊字符,则不能原样使用 表单数据。
      5. 因此,Apigee Edge 会以 500 Internal Server Error(包含错误代码) protocol.http.BadFormData

    实际请求

    如需使用实际请求进行验证,请执行以下操作:

    1. 如果您无权访问向目标服务器发出的实际请求 然后找到分辨率
    2. 如果您有权访问向 Apigee Edge 发出的实际请求,请执行 执行下列步骤: <ph type="x-smartling-placeholder">
        </ph>
      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 请求的一部分发送的客户端始终会按照 Form Data - 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 的内容

    使用 <ph type="x-smartling-placeholder"></ph> percent-encoding 表示百分号 (%),即将文件修改为 %25 ,如下所示:

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

规范

Apigee Edge 应根据以下规范发送表单数据

规范
<ph type="x-smartling-placeholder"></ph> 表单数据 - application/x-www-form-urlencoded

如果您仍需要 Apigee 支持团队的任何帮助,请参阅必须收集 诊断信息

必须收集的诊断信息

按照上述说明操作后,如果问题依然存在,请收集以下内容 然后联系 Apigee Edge 支持团队

如果您是公有云用户,请提供以下信息:

  • 组织名称
  • 环境名称
  • API 代理名称
  • 完整的 curl 命令,用于重现 500 Internal Server Error(包含错误代码) protocol.http.BadFormData
  • API 请求的跟踪文件

如果您是 Private Cloud 用户,请提供以下信息:

  • 观察到失败请求的完整错误消息
  • 环境名称
  • API 代理软件包
  • 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

参考