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 格式

单一编码 压缩

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

请参阅 RFC1950 RFC1951.

多种编码

多种编码

例如,如果编码进行了两次,则可能发生以下情况:

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

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

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

常见诊断步骤

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

API 监控

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

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

  3. 前往 Analyze > API Monitoring > Investigate 页面。
  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. 如果故障来源的值为 proxy,则表示请求载荷格式与 Content-Encoding 标头中指定的 支持的编码不匹配。

跟踪工具

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

  1. 启用跟踪会话,并执行以下任一操作:
    1. 等待 400 Bad Request 错误发生,或者
    2. 如果您可以重现问题,请发出 API 调用并重现 400 Bad Request
  2. 确保已启用 Show all FlowInfos

  3. 选择其中一个失败的请求并检查跟踪记录。
  4. 浏览跟踪记录的不同阶段,并找到发生故障的位置。
  5. 您通常会在 Request Received from Client 阶段后立即在流程中发现错误,如下所示:

    查看大图

  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 返回的状态代码和错误消息。

    进入跟踪记录中的 Response Sent to Client 阶段,如下所示:

    查看大图

    请注意跟踪记录中的以下详细信息:

    • 状态代码400 Bad Request
    • 错误内容{"fault":{"faultstring":"Decompression failure at request","detail":{"errorcode":"messaging.adaptors.http.flow.DecompressionFailureAtRequest"}}}
  9. 进入跟踪记录中的 AX(已记录的 Analytics 数据)阶段并点击该阶段。

  10. 向下滚动到 Phase Details(阶段详细信息)和 Error Headers(错误标头)部分,并确定 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. 如果您是 Private Cloud 用户,则可以使用 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-code X-Apigee-fault-code 的以下值:

    响应标头
    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. 示例轨迹中的值如下所示:

      • 内容编码gzip
      • 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

    消息处理器日志

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

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

    1. 使用 API 监控、跟踪工具或 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 会抛出异常,并向客户端应用返回包含错误代码 messaging.adaptors.http.flow.DecompressionFailureAtRequest400 状态代码。

      情景 #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 会抛出异常,并向客户端应用返回包含错误代码 messaging.adaptors.http.flow.DecompressionFailureAtRequest400 状态代码。

分辨率

  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 请求的跟踪文件

如果您是 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