400 Bad Request - 解压缩失败的 Request

您正在查看 Apigee Edge 文档。
前往 Apigee X 文档
信息

问题

客户端应用收到 HTTP 状态代码 400 Bad Request(错误代码为 messaging.adaptors.http.flow.DecompressionFailureAtRequest ),以此响应 API 调用。

出错提示

客户端应用获取以下响应代码:

HTTP/1.1 400 Bad Request

此外,您可能会看到类似如下所示的错误消息:

{
   "fault":{
      "faultstring":"Decompression failure at request",
      "detail":{
         "errorcode":"messaging.adaptors.http.flow.DecompressionFailureAtRequest"
      }
   }
}

可能的原因

仅在以下情况下,会发生此错误:

  • HTTP 请求标头 Content-Encoding 中指定的编码有效且 受 Apigee Edge 支持
  • 但是

  • 客户端作为 HTTP 请求的一部分发送的载荷格式与 Content-Encoding 标头中指定的编码格式不匹配

这是因为 Apigee Edge 无法使用指定的编码对载荷进行解码,因为载荷的格式与 Content-Encoding 标头中指定的编码格式不一致。

以下是一些受支持的 Content-Encoding 值示例,以及 Apigee Edge 在这些情况下对载荷格式的要求:

场景 Content-Encoding 预期载荷格式
单次编码 gzip

Unix gzip 格式。

请参阅 RFC1952 GZIP 格式

单次编码 deflate

此格式使用 zlib 结构和 deflate 压缩算法。

请参阅 RFC1950 RFC1951.

多重编码

多重编码

例如,如果编码执行两次,则可能出现以下情况:

  • gzip、deflate
  • gzip、gzip
  • deflate、gzip
  • deflate、deflate
按标头中显示的顺序对载荷应用了多种编码。

造成此错误的可能原因如下:

原因 说明 适用的问题排查说明
请求载荷格式与 Content-Encoding 标头中指定的编码不匹配 客户端发送的请求载荷的格式未经过编码,或者与 Content-Encoding 标头中指定的编码不匹配。 Edge Public 和 Private Cloud 用户

常见诊断步骤

您可以使用以下工具/方法来诊断此错误:

API 监控

如需使用 API 监控功能诊断错误,请执行以下操作:

  1. 以具有 适当角色的用户身份 登录 Apigee Edge 界面
  2. 切换到您要调查问题的组织。

  3. 前往分析 > API 监控 > 调查页面。
  4. 选择您发现错误的具体时间范围。
  5. 确保将代理过滤条件设置为全部
  6. 绘制故障代码时间的对比图。
  7. 选择具有故障代码 messaging.adaptors.http.flow.DecompressionFailureAtRequest 的电池,如下所示:

    查看放大图片

  8. 系统会显示有关故障代码 messaging.adaptors.http.flow.DecompressionFailureAtRequest 的信息,如下所示:

    查看放大图片

  9. 点击查看日志,然后展开因 400 错误而失败的行。

    查看放大图片

  10. 日志窗口中,记下以下详细信息:
    • 状态代码400
    • 故障来源proxy
    • 故障代码messaging.adaptors.http.flow.DecompressionFailureAtRequest
  11. 如果 Fault Source 的值为 proxy,则表示请求载荷格式与 Content-Encoding 标头中指定的 支持的编码不匹配。

Trace 工具

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

  1. 启用跟踪会话,然后执行以下任一操作:
    1. 等待 400 Bad Request 错误发生,或
    2. 如果您可以重现该问题,请进行 API 调用并重现 400 Bad Request
  2. 确保已启用显示所有 FlowInfo

  3. 选择一个失败的请求,然后检查轨迹。
  4. 浏览轨迹的不同阶段,找到发生故障的位置。
  5. 您通常会在收到来自客户端的请求阶段之后的流程中发现该错误,如下所示:

    查看放大图片

  6. 请记下轨迹中属性的值:

    • 错误Decompression failure at request
    • error.classcom.apigee.rest.framework.BadRequestException
    • error.cause:Not in GZIP format

    error.cause 表明请求载荷不是 GZIP 格式。 这意味着,Apigee Edge 预期请求载荷采用 GZIP 格式,因为 Content-Encoding 标头中会指定该格式。

  7. 确定请求标头 Content-Encoding 的值。 为此,请前往阶段 Request Received from Client,如下所示:

    查看放大图片

    请注意,请求标头 Content-Encoding 的值确实为 gzip

    上述示例跟踪记录显示,请求标头 Content-Encoding 中指定的编码为 gzip;但是,请求载荷不是 GZIP 格式。因此,Apigee 无法使用 gzip 解压缩载荷,并返回错误 Decompression failure at request

  8. 请注意 Apigee Edge 返回的状态代码和错误消息,方法是前往

    到轨迹中的发送给客户端的响应阶段,如下所示:

    查看放大图片

    请注意轨迹中的以下详细信息:

    • 状态代码400 Bad Request
    • 错误内容{"fault":{"faultstring":"Decompression failure at request","detail":{"errorcode":"messaging.adaptors.http.flow.DecompressionFailureAtRequest"}}}
  9. 在轨迹中找到 AX(记录的分析数据)阶段,然后点击它。

  10. 向下滚动到阶段详情错误标头部分,并确定 X-Apigee-fault-codeX-Apigee-fault-source 的值,如下所示:

    查看放大图片

  11. 您将看到 X-Apigee-fault-codeX-Apigee-fault-source 的值分别为 messaging.adaptors.http.flow.DecompressionFailureAtRequestpolicy,这表示请求载荷格式与 Content-Encoding 标头中指定的编码不匹配。
    响应标头
    X-Apigee-fault-code messaging.adaptors.http.flow.DecompressionFailureAtRequest
    X-Apigee-fault-source policy

NGINX

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

  1. 如果您是私有云用户,则可以使用 NGINX 访问日志来确定有关 HTTP 400 错误的关键信息。
  2. 检查 NGINX 访问日志:

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

    其中ORGENVPORT# 会替换为实际值。

  3. 搜索以查看特定时间段内(如果问题发生在过去)是否存在任何 400 错误,或者是否仍有请求失败并显示 400
  4. 如果您发现任何 400 错误,且 X-Apigee-fault-codemessaging.adaptors.http.flow.DecompressionFailureAtRequest 的值匹配,请确定 X-Apigee-fault-source 的值。

    NGINX 访问日志中的 400 错误示例

    上述 NGINX 访问日志中的示例条目具有以下 X-Apigee-fault-codeX-Apigee-fault-source 值:

    响应标头
    X-Apigee-fault-code messaging.adaptors.http.flow.DecompressionFailureAtRequest
    X-Apigee-fault-source policy

原因:请求载荷格式与 Content-Encoding 标头中指定的编码不匹配

默认情况下,如果请求标头 Content-Encoding 包含有效且受支持的编码,Apigee Edge 会始终解压缩载荷。因此,请求载荷的格式应与请求标头 Content-Encoding 中指定的编码相匹配。 如果存在不匹配,您会收到此错误。

诊断

  1. 使用 API 监控、Trace 工具或 NGINX 访问日志(如常见诊断步骤中所述)确定所观测到的错误的故障代码故障来源
  2. 如果故障代码messaging.adaptors.http.flow.DecompressionFailureAtRequest,且故障来源的值为 policyproxy,则表示客户端应用发送的请求具有与请求标头 Content-Encoding 中指定的 支持的编码不匹配的载荷。
  3. 您可以使用以下任一方法在 HTTP 请求中确定不匹配情况:

    出错提示

    使用错误消息进行验证:

    1. 如果您有权访问从 Apigee Edge 收到的完整错误消息,请参阅 faultstring

      示例错误消息

      "faultstring":"Decompression failure at request"
    2. 在上述错误消息中,系统显示了 "Decompression failure at request",这表示无法使用 Content-Encoding 标头中指定的编码来解压缩请求

    跟踪记录

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

    1. 使用 Trace 确定请求标头 Content-Encoding 和属性 error.cause 的值,如常见诊断步骤中所述。
    2. 示例轨迹中的值如下所示:

      • Content-Encodinggzip
      • error.cause:Not in GZIP format

      请求标头 Content-Encoding 中的值为 gzip;但是,请求载荷不是 GZIP 格式(如 error.cause 所示)。因此,Apigee Edge 会返回 400 Bad Request 和错误代码 messaging.adaptors.http.flow.DecompressionFailureAtRequest

    实际请求

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

    如果您有权访问客户端应用发出的实际请求,请执行以下步骤:

    1. 确定传递给请求标头 Content-Encoding 的值。
    2. 确定作为请求的一部分发送的载荷的格式。
    3. 如果 Content-Encoding 标头的值在 支持的编码列表中,但请求载荷的格式与 Content-Encoding 标头中指定的编码不匹配,则这是问题的原因。

      示例请求

      curl -v "http://HOSTALIAS/v1/testgzip" -H "Content-Encoding: gzip" -X POST -d @request_payload.zip
      

      上述示例请求将值 gzip 发送到 Content-Encoding 标头,该标头是 Apigee Edge 中 支持的编码。不过,请求载荷 request_payload.zip 采用 ZIP 格式。因此,此请求失败,并返回 400 Bad Request 状态代码和错误代码:messaging.adaptors.http.flow.DecompressionFailureAtRequest

    消息处理器日志

    如需使用消息处理器日志进行验证,请执行以下操作:

    如果您是私有云用户,则可以使用消息处理器日志来确定有关 HTTP 400 错误的关键信息。

    1. 使用 API 监控、Trace 工具或 NGINX 访问日志确定失败请求的消息 ID,如常见诊断步骤中所述。
    2. 在消息处理器日志中搜索消息 ID:

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

    3. 您会看到以下某一种异常:

      情景 #1

      情形 1:当 API 请求具有标头 Content-Encoding: gzip 时

      2021-07-28 10:21:16,861  NIOThread@0 ERROR HTTP.SERVER -
      HTTPServer$Context.onInputException() : Message id:rt-57-1
      SSLClientChannel[Accepted: Remote:192.168.199.8:8443
      Local:192.168.80.234:44284]@28469 useCount=1 bytesRead=0
      bytesWritten=28764 age=2739893ms  lastIO=0ms
      isOpen=true.onExceptionRead exception: {}
      java.util.zip.ZipException: Not in GZIP format
      
      2021-07-28 10:21:16,862  NIOThread@0 ERROR ADAPTORS.HTTP.FLOW -
      AbstractRequestListener.onException() : Request:POST, uri:/test,
      message Id:rt-57-1, exception:java.util.zip.ZipException: Not in GZIP format,
      context:Context@71ea5ac input=ClientInputChannel(SSLClientChannel[Accepted:
      Remote:192.168.199.8:8443 Local:192.168.80.234:44284]@28469 useCount=1
      bytesRead=0 bytesWritten=28764 age=2739894ms  lastIO=0ms  isOpen=true)
      2021-07-28 10:21:16,862  NIOThread@0 INFO  HTTP.SERVICE -
      ExceptionHandler.handleException() :
      Exception java.util.zip.ZipException: Not in GZIP format occurred while writing
      to channel null
      2021-07-28 10:21:16,863  NIOThread@0 INFO  HTTP.SERVICE -
      ExceptionHandler.handleException() : Exception trace:
      java.util.zip.ZipException: Not in GZIP format
      

      上述错误消息中的 java.util.zip.ZipException: Not in GZIP format 行表明,虽然 Content-Encoding 指定为 gzip,但请求载荷并未以 GZIP 格式发送。因此,Apigee Edge 会抛出异常,并向客户端应用返回 400 状态代码和故障代码 messaging.adaptors.http.flow.DecompressionFailureAtRequest

      情景 #2

      情形 2:当 API 请求具有标头 Content-Encoding: deflate 时

      2021-07-28 15:26:31,893  NIOThread@1 ERROR HTTP.SERVER -
      HTTPServer$Context.onInputException() : Message id:rt-47875-1
      SSLClientChannel[Accepted: Remote:192.168.199.8:8443
      Local:192.168.81.72:45954]@29276 useCount=1 bytesRead=0
      bytesWritten=37230 age=3498856ms  lastIO=1ms
      isOpen=true.onExceptionRead exception: {}
      java.util.zip.ZipException: incorrect header check
                        ….
      Caused by: java.util.zip.DataFormatException: incorrect header check
             ..
      2021-07-28 15:26:31,894  NIOThread@1 ERROR ADAPTORS.HTTP.FLOW -
      AbstractRequestListener.onException() : Request:POST, uri:/test,
      message Id:rrt-47875-1, exception:java.util.zip.ZipException:
      incorrect header check, context:Context@69b3ac45
      input=ClientInputChannel(SSLClientChannel[Accepted:
      Remote:192.168.199.8:8443 Local:192.168.81.72:45954]@29276
      useCount=1 byt	esRead=0 bytesWritten=37230 age=3498856ms
      lastIO=1ms  isOpen=true)
      

      上述错误消息中的 java.util.zip.ZipException: incorrect header checkCaused by: java.util.zip.DataFormatException: incorrect header check 行表示请求载荷未以 deflate 格式发送,并且与 deflate 的 Content-Encoding 标头中指定的编码不匹配。因此,Apigee Edge 会抛出异常,并向客户端应用返回 400 状态代码和故障代码 messaging.adaptors.http.flow.DecompressionFailureAtRequest

分辨率

  1. 如果 Apigee Edge 中的 API 代理流程和后端服务器不需要压缩的请求载荷,则不要传递标头 Content-Encoding。如果需要压缩请求载荷,请前往第 2 步。
  2. 确保客户端应用始终发送以下内容:
    • 将任何 支持的编码作为请求中 Content-Encoding 标头的值
    • 发送到 Apigee Edge 的请求载荷采用受支持的格式,并且与 Content-Encoding 标头中指定的编码格式相匹配
  3. 在上述示例中,请求载荷采用 ZIP 格式,但请求标头指定了 Content-Encoding: gzip。您可以通过以下方式解决此问题:将请求标头作为 Content-Encoding: gzip 发送,并将请求载荷也采用 gzip 格式:
    curl -v "https://HOSTALIAS/v1/testgzip" -H "Content-Encoding: gzip" -X POST -d @request_payload.gz
    

规范

根据以下 RFC 规范,Apigee Edge 会返回状态代码 400 Bad Request 和错误代码 messaging.adaptors.http.flow.DecompressionFailureAtRequest

规范
RFC 7231 第 6.5.1 节
RFC 7231 第 3.1.2.2 节

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

必须收集的诊断信息

收集以下诊断信息,然后与 Apigee Edge 支持团队联系:

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

  • 组织名称
  • 环境名称
  • API 代理名称
  • 用于重现 400 错误的完整 curl 命令
  • API 请求的轨迹文件

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

  • 失败请求的完整错误消息
  • 环境名称
  • 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