流式转发不能依赖默认配置,因mod_proxy_http默认缓冲整个请求体并重写Content-Length,导致高延迟、内存溢出或超时中断;必须显式配置disablereuse=off、keepalive=on及ProxyPass nocanon,并协同调整Timeout、KeepAliveTimeout等主进程超时参数。

流式转发为什么不能依赖默认配置
Apache mod_proxy_http 默认会缓冲整个请求体(request body)再转发,这对大文件上传、SSE(Server-Sent Events)、日志尾部流(tail -f 类接口)或分块上传场景非常致命:缓冲行为导致首字节延迟高、内存占用陡增,甚至触发 ProxyError: request body too large 或被后端超时中断。
根本原因在于,mod_proxy_http 为兼容各种后端,默认启用内部缓冲和 Content-Length 重写逻辑 —— 它试图“规范化”请求,但流式场景恰恰需要绕过这种规范化。
必须禁用的三项默认行为
要实现真正流式转发,以下三处配置缺一不可,且顺序和位置敏感:
-
ProxySet disablereuse=off—— 必须显式设为off(默认是on),否则 Apache 会在每次转发后关闭连接,破坏 HTTP/1.1 持久连接,导致流式传输中途断连 -
ProxySet keepalive=on—— 启用长连接复用,避免每个 chunk 都重建 TCP 连接;配合disablereuse=off才生效 - 禁用
ProxyPassReverse对Content-Length的自动重写:Apache 默认会抹掉原始Content-Length并重新计算,而流式请求往往不带该头或值为chunked。解决方法是在ProxyPass后加nocanon标志,并确保后端返回的响应头未被意外篡改
Java/Spring Boot 流式接口的典型配置片段
假设后端是 Spring Boot 提供 SSE 接口 /api/events,需透传原始请求头、禁用缓冲、保持连接:
<proxy>
ProxySet keepalive=on
ProxySet disablereuse=off
ProxySet timeout=300
</proxy>
ProxyPass "/api/events" "http://10.0.1.5:8080/api/events" nocanon
ProxyPassReverse "/api/events" "http://10.0.1.5:8080/api/events"
关键点:
-
nocanon防止 Apache 对路径做 URI 解码重写,避免 SSE 中的特殊字符(如data:行)被破坏 -
timeout=300是针对该后端连接池的空闲超时,必须 ≥ 后端 SSE 心跳间隔(如 30s)× 2,否则连接被提前回收 - 务必确认后端响应中包含
Content-Type: text/event-stream和Cache-Control: no-cache,Apache 不会修改这些头,但若后端漏发,流式将失效
容易被忽略的协同点:Apache 主进程级超时
即使代理层配置正确,Apache 主配置中的 Timeout 和 KeepAliveTimeout 仍会覆盖代理行为:
-
Timeout 300—— 必须 ≥ 后端最长单次流式响应耗时(如 SSE 连接维持 5 分钟,则设为 300) -
KeepAliveTimeout 5—— 控制客户端到 Apache 的空闲长连接超时,不影响后端连接;但若设得太小(如 2),会导致客户端频繁重连,干扰流式体验 - 若使用
mod_reqtimeout,需检查RequestReadTimeout是否对 POST/PUT 请求设置了过短的minrate,它可能在流式上传中途 kill 连接
流式转发不是加一个参数就能跑通的事——它是代理层、连接池、主进程超时、后端协议支持四者咬合的结果。少调一处,就可能表现为“前 10KB 正常,之后卡住”或“每 60 秒自动断连”。











