使用 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 ()
该问题的症状与以下案例和错误类似,但日志中的错误不同:
- 使用 mod_proxy 对 SOAP 服务进行反向代理时出现间歇性错误
- https://bz.apache.org/bugzilla/show_bug.cgi?id=37770#c88
- https://bz.apache.org/bugzilla/show_bug.cgi?id=48037
我尝试了以下环境变量的各种组合,但没有成功:
- 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 版本中得到修正