当后端在上传大文件时发送 401 时,Apache 2.4 会发送 502 错误

当后端在上传大文件时发送 401 时,Apache 2.4 会发送 502 错误

使用 Apache 2.4.25(Windows)和后端服务器 Tomcat 8(Windows)。

我们有一些客户端软件,它使用 HTTPS 在通过 Apache 代理到 Tomcat 的经过身份验证的会话上上传文件。但是,如果没有使用经过身份验证的会话(或会话超时),后端 Tomcat 服务器会发送 HTTP 401 响应。然而,Apache 却向客户端返回 502 错误。

Tomcat访问日志:

127.0.0.1 - - [21/Apr/2017:18:30:38 +0000] "POST /upload/10507.wav HTTP/1.1" 401 39

Apache 访问日志:

10.8.21.23 - - [21/Apr/2017:18:30:27 +0000] "POST /upload/10507.wav HTTP/1.1" 502 232 14030

Apache 错误日志:

[Fri Apr 21 18:30:39.770715 2017] [proxy:error] [pid 33652:tid 120896] (OS 10053)An established connection was aborted by the software in your host machine.  : [client 10.8.21.23:62863] AH01084: pass request body failed to 127.0.0.1:8888 (127.0.0.1)
[Fri Apr 21 18:30:39.770715 2017] [proxy_http:error] [pid 33652:tid 120896] [client 10.8.21.23:62863] AH01097: pass request body failed to 127.0.0.1:8888 (127.0.0.1) from 10.8.21.23 ()

该问题的症状与以下案例和错误类似,但日志中的错误不同:

我尝试了以下环境变量的各种组合,但没有成功:

  • SetEnv 强制代理请求-1.0 1
  • SetEnv 代理-nokeepalive 1
  • SetEnv 代理初始非池化 1
  • RequestHeader 未设置 提前预期
  • SetEnv 代理发送 1

对于请求体较小的请求,它会按预期代理 401。对于较大的请求(> 1MB 左右,但不一致),它会发送 502。后端处理不必在决定会话是否存在之前读取整个正文,因此它可以在读取标头后立即触发 401。对于超过 10MB 的文件,即使代理到本地后端服务器,也可以 100% 地重现它。

推测这是因为 Apache 在收到 401 响应之前没有完全读取整个请求。它将此视为“代理错误”,而不是传递“正确的”401 响应。

我们尝试使用不同的负载均衡器(AWS ELB),它在所有情况下都会返回 401,因此我怀疑发送 502 是否是预期行为。

我是否缺少任何 Apache 环境变量来尝试?这是 Apache 错误吗?

答案1

修复方法是修改 Tomcat 配置中的“maxSwallowSize”,使得 Tomcat 在发送响应之前吞下字节数。

https://tomcat.apache.org/tomcat-8.0-doc/config/http.html

最大吞咽量

Tomcat 中止上传时将接受的最大请求主体字节数(不包括传输编码开销)。中止上传是指 Tomcat 知道请求主体将被忽略但客户端仍然发送它。如果 Tomcat 不接受主体,客户端不太可能看到响应。如果未指定,将使用默认值 2097152(2 兆字节)。小于零的值表示不应强制执行任何限制。

答案2

Apache 中的错误https://bz.apache.org/bugzilla/show_bug.cgi?id=60330 希望在 2.4.40 版本中得到修正

相关内容